对于我正在处理的网站,我们正在改进一种资源的网址 - 特别是从数字ID转向唯一的描述性字符串。类似的例子是从通过数字数据库ID识别用户切换到通过用户名识别它们(不是我们的具体情况,而是类似的)。因此,访问用户信息的URL看起来像:
/users/48573
现在看起来像是
/users/thisisausername.
唯一的问题是,我们仍然需要能够以某种方式通过数字ID获取它们,这是API的传统消费者。我们不需要REST URL本身来重定向(例如/users/48573
不应该重定向到/users/thisisausername
),我们只需要一种方法来使用旧标识符获取正确的数据。该解决方案应该提供另一种方式来访问用户信息(方便地包括新标识符,用户名),或者通过ID访问用户名。一些可能的解决方案可能是:
/users/byid/48573
/users/48573?fetchby=id
或/users/48573?byid=true
/identifiers/username/48573
哪些(如果有的话)最接近正确的REST?你会如何处理这个问题?
答案 0 :(得分:31)
我认为添加路径段/前缀是最好的答案。由于这些是唯一的二级密钥,这与搜索(返回一组项目)不同,因此使用查询参数(未缓存)似乎不是最佳选择。
就个人而言,我打算使用由“=”分隔的路径段前缀,例如“name =”或“email =”:
user/123456
user/name=john.doe
user/email=john.doe@john.doe
这在功能上等同于添加路径段(例如“user / name / john.doe”),但我觉得它更接近于概念模型。当然,这是一个无关紧要的细节,因为RESTful API不应该指定固定的URI结构。
不使用查询参数也允许自然访问子资源:
user/name=john.doe/inbox/df87bhJXrg63
像Java的JAX-RS这样的框架支持使用你想要的任何分隔符:
@GET
@Path("user/{id}")
User getUser(@PathParam("id") UUID id);
@GET
@Path("user/name={name}")
User getUserByName(@PathParam("name") String name);
@GET
@Path("user/email={email}")
User getUserByEmail(@PathParam("email") String email);
答案 1 :(得分:16)
你的第一个选择可能是最好的。
按ID搜索用户:
/users/id/48573
按短名称搜索用户:
/users/name/thisisausername
如果他们遗漏了该路径参数,您可以始终默认使用新的短用户名格式。
我看到的另一个选项是使用如下的查询参数:
/users?id=48573
/users?name=thisisausername
我认为第一种看起来更清洁,更具可读性。
答案 2 :(得分:0)
相当古老的问题,但我有同样的,并且finnaly找到了解决方案: 在你的路径参数中使用正则表达式。
以下是我编写该用例的方法
@GET
@Path("/{id : \\d+}")
@Produces(APPLICATION_JSON)
public Response getById(@PathParam("id") long id) {
<<your code>>
}
@GET
@Path("/{name}")
@Produces(APPLICATION_JSON)
public Response getByName(@PathParam("name") String name) {
<<your code>>
}
答案 3 :(得分:-3)
我会考虑使用可选后缀限定字符串:
/users/48573/id
/users/48573/name
如果收到不带后缀的字符串:
/users/48573
然后检查字符串并查看它是ID还是名称。
如果您只获得有效的ID而不是名称,那么它的ID是相当于:
的ID/users/48573/id
如果您只返回一个名称,那么它的名称相当于:
/users/48573/name
如果您可以按ID或名称检索值,则会返回300响应错误并返回指向客户端的两种可能性的链接:
/users/48573/id
/users/48573/name
传统消费者继续“按原样”工作,除了偶尔出现重复的ID /名称对,他们收到新的300响应错误。
答案 4 :(得分:-3)
如果这是一个问题,那么您的API不是RESTful。致quote罗伊菲尔丁:
REST API不能定义固定资源名称或层次结构(客户端和服务器的明显耦合)。服务器必须能够自由控制自己的命名空间。相反,允许服务器通过在媒体类型和链接关系中定义这些指令来指示客户端如何构造适当的URI,例如在HTML表单和URI模板中完成的。 [这里的失败意味着客户端由于带外信息而假定资源结构,例如特定于域的标准,这是面向数据的,与RPC的功能耦合等效。]
应输入REST API,除了初始URI(书签)和适用于目标受众的标准化媒体类型集之外没有任何先验知识(即,任何可能使用API的客户都应该理解)。从那时起,所有应用程序状态转换必须由客户端选择服务器提供的选择来驱动,这些选择存在于接收的表示中或者由用户对这些表示的操纵所暗示。转换可以由客户端对媒体类型和资源通信机制的知识来确定(或限制),这两者都可以在运行中(例如,按需代码)进行改进。 [失败在这里意味着带外信息驱动交互而不是超文本。]