REST – 支持多种可能的标识符

对于我正在处理的网站,我们正在改进我们针对某种资源types的url,特别是从数字ID转向唯一的描述性string。 一个类似的例子是从数字数据库ID识别用户到通过用户名(而不是我们特定的情况,但是类似的)识别用户。 因此,访问用户信息的URL过去如下所示:

/users/48573 

现在看起来像

 /users/thisisausername. 

唯一的问题是,我们仍然需要能够以某种方式通过数字ID获取它们,对于API的传统消费者。 我们不需要自己redirectREST URL(例如/users/48573不应该redirect到/users/thisisausername ),我们只需要一种方法来使用旧的标识符来获取正确的数据。 该解决scheme应该提供一种通过ID访问用户信息(方便地包括新标识符,用户名)或通过ID访问用户名的另一种方式。 一些可能的解决办法可能是

  • 使用节点来指定一些替代的标识方法,例如/users/byid/48573
  • 使用查询参数指定一些替代方法的标识,例如/users/48573?fetchby=id/users/48573?byid=true
  • 将用户名作为另一个资源处理,例如/identifiers/username/48573

哪些(如果有的话)最接近正确的REST? 你将如何处理这个问题?

我认为添加一个path段/前缀是最好的答案。 由于这些是唯一的辅助键,这不同于search(它返回一组项目),所以使用查询参数(没有caching)似乎不是最好的select。

就个人而言,我打算使用由“=”分隔的path段前缀,如“name =”或“email =”:

 user/123456 user/name=john.doe user/email=john.doe@john.doe 

这在function上等同于添加一个path段(例如“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); 

你的第一个select可能是最好的。

通过IDsearch用户:

 /users/id/48573 

通过短名称search用户:

 /users/name/thisisausername 

如果他们忽略该path参数,则可以始终默认为新的简短用户名格式。

我已经看到的另一个选项是使用如下的查询参数:

 /users?id=48573 /users?name=thisisausername 

我认为第一个看起来更干净,更可读。

一个古老的问题,但我有相同的Finnaly发现解决scheme:在你的path参数使用正则expression式。

这是我如何编码的用例

 @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>> } 

我会考虑使用一个可选的后缀限定string:

 /users/48573/id /users/48573/name 

如果您收到一个没有后缀的string:

 /users/48573 

那么你检查string,看看它是一个ID或名称。

如果你只有一个有效的ID,但没有一个名字,那么这是一个ID检索相当于:

 /users/48573/id 

如果你只有一个名字,那么这是一个名称检索相当于:

 /users/48573/name 

如果您可以通过ID或名称检索值,则返回300响应错误,并返回到客户端的可能性链接:

 /users/48573/id /users/48573/name 

传统消费者继续“按原样”工作,除偶尔发生重复的ID /姓名对,他们收到新的300响应错误。

如果这是一个问题,您的API不是RESTful。 引用 Roy Fielding的话:

REST API不能定义固定的资源名称或层次结构(客户端和服务器明显的耦合)。 服务器必须有自由来控制自己的命名空间。 相反,允许服务器通过在媒体types和链接关系中定义这些指令来指导客户如何构build适当的URI,例如在HTML表单和URI模板中完成。 [这里的失败意味着客户端由于带外信息(例如特定于领域的标准,这是面向数据的RPC等效于RPC的function耦合)正在假设资源结构)。

除了最初的URI(书签)和适合于目标受众的标准化媒体types(即预期被任何可能使用API​​的客户端所理解)的集合之外,REST API应该在没有任何先前知识的情况下被input。 从那时开始,所有应用程序状态转换必须由客户机select服务器提供的select来驱动,这些select出现在所接收的表示中或者由用户对这些表示的操作所暗示。 客户对媒体types和资源通信机制的了解可以决定(或限制)转换,这两种转换都可以即时改进(例如,按需编码)。 [这里的失败意味着带外信息正在推动互动,而不是超文本]。