REST API设计-通过具有不同参数但URL模式相同的REST获取资源


92

我有一个与REST网址设计有关的问题。我在这里找到了一些相关的文章:相同资源的不同RESTful表示形式以及此处:不同字段的RESTful到GET资源的url,但是关于最佳实践是什么以及为什么还不清楚。这是一个例子。

我有代表“用户”资源的REST网址。我可以使用ID或电子邮件地址来获取用户,但两者的URL表示形式均相同。通过浏览许多博客和书籍,我发现人们一直在以许多不同的方式来进行此操作。例如

在书中以及stackoverflow上的某处阅读此练习(我似乎再也找不到链接了)

GET /users/id={id}
GET /users/email={email}

在许多博客上阅读这种做法

GET /users/{id}
GET /users/email/{email}

查询参数通常用于过滤由url表示的资源的结果,但是我也看到了这种做法

GET /users?id={id}
GET /users?email={email}

我的问题是,在所有这些实践中,哪种方法最适合使用api的开发人员,为什么?我相信,关于REST网址设计和命名约定,没有固定的规则,但是我只是想知道我应该采取哪种方式来帮助开发人员更好地理解API。

所有帮助表示赞赏!


1
我知道这有点旧,但是在寻找类似资源时,我偶然发现了这个问题以及您正在寻找的资源。我相信就是这个stackoverflow.com/a/9743414/468327
Joel Berger

Answers:


102

以我的经验,这GET /users/{id} GET /users/email/{email}是最常见的方法。如果用户与提供的id或不存在,我还希望方法返回404 Not Found email。我也不会感到惊讶GET /users/id/{id}(尽管我认为这是多余的)。

对其他方法的评论

  1. GET /users/id={id} GET /users/email={email}
    • 我认为我没有看过,如果我看过,那将非常令人困惑。几乎就像它试图模仿带有路径参数的查询参数一样。
  2. GET /users?id={id} GET /users?email={email}
    • 当您提到使用查询参数进行过滤时,我认为您的想法令人震惊。
    • 它会永远是有意义的称之为资源与两者idemail(例如GET /users?id={id}&email={email})?如果没有,我不会使用像这样的单一资源方法。
    • 我希望使用此方法来检索具有可选查询参数的用户列表以进行过滤,但我不会期望idemail或者任何唯一标识符都在参数之中。例如:GET /users?status=BANNED可能返回禁止用户列表。

查看有关问题的答案


谢谢你的反馈。其实你是对的。好像我在《 RESTful Java with Jax-rs》一书中读过#1,但有点脱离上下文。但是我非常清楚地记得读过这篇文章,作为对stackoverflow本身的一个问题的答案(相信我,当我说我也正在努力寻找该链接以证明给我的同事们:)时),而#2正是我的本意。寻找。有关设计的一些反馈。谢谢!
shahshi15 2013年

PS:我不确定在这里发布是否违反规定,但是您可能也可以对我的其他问题之一有所了解?请?:) stackoverflow.com/questions/20508008/...
shahshi15

只是为了澄清您对的冗余声明/users/id/{id},这允许扩展功能,仅允许通过多个标识符(id,guid,name)访问一个资源。在这里
丹尼尔·杜波夫斯基

4
我的回答是,例如,引用特定用户的适当方法是/ users / {id}。如果您想通过特定的电子邮件地址查找用户,而该地址不是用户的唯一标识符,我会执行/ users?email = {email},因为这是一种过滤用户集合的方式,而不是通过其资源来标识一个特定资源标识符为/ users / {id}。
凯文M

好答案!为此竖起大拇指。我建议做的唯一一件事就是更改您的API,因为REST应该以名称为中心,因此您的资源映射应该是这样的:GET /user/1234而不是GET /users/123
Sammy,

36

务实地看待这个问题,您已经拥有了许多用户:

/users   # this returns many

每个用户都有一个专用的资源位置:

/users/{id}    # this returns one

您还可以通过多种方式搜索用户:

/users?email={email}
/users?name=*bob*

由于这些都是/ users的查询参数,因此它们都应返回列表..即使它是1的列表。

我在这里写了一篇关于实用RESTful API设计的博客文章,其中讨论了这一点,其中包括:http : //www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api


感谢您的回复vinay。但是,如果从另一个角度考虑,{email}就像{id}一样总是要返回一个结果。如果我们真的在搜索,为什么不像电子邮件一样使用?id = {id}?我想知道是否还有一致性。PS:stackoverflow的新手,不知道我只能回答一个答案。但是,谢谢您的回复!欣赏它。也许你可以帮我这一个还有:stackoverflow.com/questions/20508008/...
shahshi15

7
这就是API设计的“设计”方面发挥作用的地方。您的资源应具有专用位置。位置在哪里 位置是按ID排列的吗?如果是这样,那么您就不必按ID“搜索”,而要按ID“获取”。但是您搜索其他所有内容。当然,这里没有硬性规定。这只是一个观点:)
Vinay Sahni 2013年

6
我还认为这种方式使您的API更稳定。您确实知道自己的ID是唯一的,但是您真的确定电子邮件地址吗?即使它是唯一的,它也可能不是永久的,因为用户可以更改它。因此,/ users?email = {email}清楚地表明,这确实是一个查询,并且无法访问带有永久标识符的资源。
lex82

我相信这实际上是更正确的答案。通过电子邮件地址过滤集合可能是基于通配符的,因此它不会总是只返回一个结果。
凯文M

@VinaySahni您对类似这样的模式有何看法:/user?by=email&email="abc@pqr.com“ / user?by = id&id =” xashkhx“ / users?filterA =” a“&filterB =” b“(多(适用于多个用户)
Shasak

2

关于用户资源

在路径上,/users您将始终获得返回的用户资源的集合。

在这条路上,/users/[user_id]您可以预期会发生几件事:

  1. 您应该获得一个表示用户资源及其标识符[user_id]的单例资源,或者
  2. 未发现404响应如果与ID [USER_ID]没有用户存在或
  3. 一个禁止401如果你没有允许访问的用户资源。

每个单例由其路径和标识符唯一标识,然后使用它们来查找资源。单身人士不能使用多个路径。

您可以/users使用查询参数(GETParameters)查询路径。这将返回符合要求条件的用户的集合。返回的集合应包含用户资源,所有资源都应包含响应中的标识资源路径。

参数可以是集合资源中存在的任何字段;firstNamelastNameid

关于电子邮件

电子邮件可以是资源或用户资源的属性/字段。

-电子邮件作为用户的属性:

如果该字段是用户的属性,则用户响应如下所示:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: 'john.doe@example.com'
  ...
}

这意味着电子邮件没有特殊的端点,但是您现在可以通过发送以下请求通过电子邮件查找用户 /users?email=john.doe@example.com。哪一个(假设电子邮件对于用户而言是唯一的)将返回一个集合,其中包含一个与电子邮件匹配的用户项。

-电子邮件作为资源:

但是,如果来自用户的电子邮件也是资源。然后,您可以制作一个API,在其中/users/[user_id]/emails返回ID为的用户的电子邮件地址的集合user_id/users/[user_id]/emails/[email_id]返回具有user_id和['email_id']的用户的电子邮件。用作标识符的方法取决于您,但是我会坚持使用整数。您可以通过将DELETE请求发送到标识要删除的电子邮件的路径来从用户删除电子邮件。因此,例如DELETEon /users/[user_id]/emails/[email_id]会删除具有user_id的用户拥有的email_id的电子邮件。最有可能只允许该用户执行此删除操作。其他用户将收到401响应。

如果用户只能拥有一个电子邮件地址,则可以坚持使用。/users/[user_id]/email 这将返回单例资源。用户可以通过PUT在该URL上键入电子邮件地址来更新其电子邮件地址。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.