【问题标题】:REST API DESIGN - Getting a resource through REST with different parameters but same url patternREST API DESIGN - 通过 REST 获取具有不同参数但相同 url 模式的资源
【发布时间】:2013-12-21 07:54:45
【问题描述】:

我有一个关于 REST url 设计的问题。我在这里找到了一些相关的帖子:Different RESTful representations of the same resource 和这里:RESTful url to GET resource by different fields,但是对于最佳实践是什么以及为什么,这些回复并不是很清楚。这是一个例子。

我有代表“用户”资源的 REST url。我可以使用 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 url 设计和命名约定方面没有一成不变的规则,但我只是想知道我应该采取哪种方式来帮助开发人员更好地理解 api。

感谢所有帮助!

【问题讨论】:

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

标签: rest url jax-rs url-scheme url-pattern


【解决方案1】:

根据我的经验,GET /users/{id} GET /users/email/{email} 是最常见的方法。如果提供的idemail 不存在用户,我还希望这些方法返回404 Not Found。看到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}both 调用此资源是否有意义?如果不是,我不会使用这样的单一资源方法。
    • 我希望这种方法能够检索具有可选查询参数的用户列表,但我不希望idemail 或任何唯一标识符包含在参数中。例如:GET /users?status=BANNED 可能会返回被禁止用户的列表。

从相关问题中查看this answer

【讨论】:

  • 感谢您的意见。其实你是对的。似乎我在“带有 Jax-rs 的 RESTful java”一书中读到了 #1,但有些断章取义。但我非常清楚地记得读过它作为对 stackoverflow 本身问题之一的回答(相信我,当我说我正在努力寻找该链接以向我的同事证明时:) 并且 #2 正是我的寻找。对设计的一些反馈。谢谢!
  • 我的回答是引用特定用户的适当方式是 /users/{id}。如果您想通过不是用户唯一标识符的特定电子邮件地址查找用户,我会这样做 /users?email={email} 因为它是一种过滤用户集合的方法,而不是通过它的资源来识别一个特定资源/users/{id} 的标识符是。
  • 如果我有用户 ID 列表,假设我有 5 个用户 ID,那么端点会是什么样子。
  • 使用 REST 是一种不好的做法,users/email 应该是一个返回电子邮件列表的端点,users/email/{email} 应该只返回一个电子邮件或 NotFound。查询参数更适合比较路径变量
  • 我很惊讶这是经过验证的答案。我同意@mohsen-kashi,GET 用户/电子邮件应该返回电子邮件资源。我也会使用查询参数。
【解决方案2】:

从务实的角度来看,您有一组用户:

/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

【讨论】:

  • 感谢您的回复。但是如果我们从另一个角度考虑这一点,{email} 就像 {id} 总是会返回一个结果。如果我们真的在搜索,为什么不使用 ?id={id} 和电子邮件一样?我想知道是否无论如何都要保持一致。 PS:stackoverflow的新手,不知道我只能一个答案。不过谢谢你的回复!欣赏它。也许你也可以帮我解决这个问题:stackoverflow.com/questions/20508008/…
  • 这就是 API 设计的“设计”方面发挥作用的地方。您的资源应该有一个专门的位置。地点在哪里?位置是id吗?如果是这样,那么您不会通过 id “搜索”,而是通过 id “获取”。但是您搜索其他所有内容。当然,这里没有硬性规定。这只是一个观点:)
  • 我还认为这样你的 API 会更稳定。您确实知道您的 id 是唯一的,但您真的确定电子邮件地址吗?即使它是唯一的,它也可能不是永久的,因为用户可以更改它。所以 /users?email={email} 清楚地表明这确实是一个查询,而不是访问具有永久标识符的资源。
  • 我相信这实际上是更正确的答案。按电子邮件地址过滤集合可能是基于通配符的,因此它不会总是只返回一个结果。
  • @VinaySahni 你对这样的模式有什么看法: /user?by=email&email="abc@pqr.com" /user?by=id&id="xashkhx" /users?filterA="a "&filterB="b"(复数表示多个用户)
【解决方案3】:

关于用户资源

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

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

  1. 您应该获得一个代表用户资源的单例资源,其标识符为 [user_id] 或
  2. 如果不存在 ID 为 [user_id] 的用户,则返回未找到的 404 响应或
  3. 如果不允许您访问所请求的用户资源,则为禁止的 401

每个单例都由其路径和标识符唯一标识,您可以使用它们来查找资源。不能为单例使用多个路径。

可以通过查询参数(GETParameters)查询路径/users。这将返回一个包含满足请求条件的用户的集合。返回的集合应包含用户资源,所有资源都在响应中具有标识资源路径。

参数可以是集合资源中存在的任何字段; 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 请求来删除用户的电子邮件。 因此,例如/users/[user_id]/emails/[email_id] 上的DELETE 将删除由具有user_id 的用户拥有的具有email_id 的电子邮件。很可能只允许该用户执行此删除操作。其他用户会收到 401 响应。

如果用户只能拥有一个电子邮件地址,您可以坚持使用/users/[user_id]/email 这将返回一个单例资源。用户可以通过PUTting 该网址的电子邮件地址来更新他的电子邮件地址。

【讨论】:

  • 肯定,符合REST原则
  • 在我看来,这应该是经过验证的答案!
猜你喜欢
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-24
  • 2013-12-01
相关资源
最近更新 更多