27

这里的一些开发人员正在就来自RESTful API的GET 请求是否应该返回所请求资源的 ID 进行友好的(有些人会说宗教性的)讨论。让我们假设以下 GET 请求:

http://my.api.com/rest/users/23

这当前返回:

{"name": "Jim", "age": 40, "favoriteColor": "blue"}

请注意,结果集中缺少“id”。

基本上有 4 个阵营在与这个问题作斗争。

CAMP #1:当调用者发出 GET 请求时,他们已经知道 ID。因此,结果集不应包含ID。如果调用者需要此数据来启用 UI 编辑,则调用者需要通过 ID 23,也许手动将成员 {"id": 23} 添加到 JSON。
Camp #1 中的人们还争辩说,结果集中存在 ID 表明该值可以修改,当然不能。

CAMP #2:如果没有 ID,JSON 结果集就不能原生地用于 UI 表单中的编辑/更新操作。相反,AJAX 回调机制需要负责传递 ID 字段并将这些字段手动添加到结果集中。这似乎很笨拙且容易出错。UI 人员正在争论结果集“感觉”就像它缺少应该存在的数据,即 ID。

CAMP #3:这些人关心的是一致性。如果我们曾经有一个 API 返回的用户对象集合,这些对象必须包含 ID。因此,为了保持一致性,GET 的单例版本也应该包含 ID。

CAMP #4:这些人建议用户的 GET 请求可以返回包含 ID 的 HyperMedia 或 SelfLinks 形式的元数据。

这不是一个深奥的“谁是对的?” 论据,要么。我们采用的方法将决定我们 API 的形状,并影响几个开发人员在新几周内的工作量。

4

2 回答 2

23

这是一个见仁见智的问题,这不是 Stackoverflow 喜欢看到的那种问题。无论如何,我会提供我的。

您正在返回对象或资源状态的表示。ID 是该表示的一部分,因此应该包含在 JSON 数据包中。它是资源的属性。呼叫者是否知道 ID 与讨论的关系并不特别密切。CAMP #1 处于摇摇欲坠的状态。

你提出的关于收藏的观点非常相关。对retrieve-1 操作使用一种表示,对retrieve-N 操作使用另一种表示是否有意义?我想不是。

但是,您面临的问题更为普遍——传输给客户的表示中应包含哪些数据,以及在什么情况下? 在某些情况下,调用者根本不关心属性的重要子集。尤其是在检索到大量对象的情况下——与基本通信成本相比,传输数据的成本更大——您希望优化返回的内容。

所有足够成熟的 REST 协议都有能力塑造返回的数据。

例如,请参阅

  • Facebook 图形 API,http://developers.facebook.com/docs/reference/api/
  • StackExchange API v2.0 - 您可以传递一个“过滤器”对象来精确地塑造返回的内容。
  • CouchDb API -每个视图都有一个 map 函数,它决定返回什么数据。它还有一个总括查询参数 ,include_docs它指示服务器包含完整对象或仅包含元数据。(在某些情况下,您可能只需要数据计数,而不需要实际数据。)

Facebook 允许您明确指定所需的字段。

在此处输入图像描述

stackexchange API 很有趣。他们定义了一种全新类型的对象来支持整形。您可以使用 API 定义“过滤器”并将其保存在服务器端。然后在您的查询中传递一个带有过滤器 ID 的过滤器参数,返回的对象表示包括过滤器中指定的所有属性。如果没有过滤器,您将获得“默认”字段子集。要获得“所有字段”,您需要定义一个包罗万象的过滤器。

您可以在https://api.stackexchange.com/docs/answers看到这一点

...并具体查看过滤器规范对话框。

在此处输入图像描述


做事没有单一的正确方法。您需要平衡您支持的“塑造”功能的复杂性与开发成本以及将使用 API 的应用程序的需求。

于 2012-07-02T21:00:54.533 回答
3

老问题,但是自从我来这里寻找东西以来,这里又提出了另一种意见:

首先,我认为网址应该是:

http://my.api.com/rest/Users/23

不是

http://my.api.com/rest/getUsers/23

“GET”依赖于 HTTP 方法,而不是 URL。这只是命名,但有助于使事情更清楚,恕我直言。

如果您考虑这一点,则需要在具有 PUT 的同一 URL 中进行资源修改

http://my.api.com/rest/Users/23

在这种情况下,客户端需要跟踪 URL,而不是 ID。资源是否返回 ID 字段并不重要。由客户保留一张地图,说明它是从哪里获得的。

如果您尝试将资源放入不同的 URL,例如“ http://my.api.com/rest/Users/24 ”,则会出现以下几种情况:

1) http://my.api.com/rest/Users/24已经存在于服务器上并且服务器接受资源作为更新

2) http://my.api.com/rest/Users/24在服务器上不存在并且:

a) 服务器接受用户正在向不存在的资源提供 ID (24)(不推荐) b) 服务器接受 PUT 作为 POST

在 a + b 中,服务器将创建一个新资源。

所以:

1)根据您对客户端的信任程度,您可能应该在服务器上创建一个“签入/签出”控件以避免用另一个资源覆盖一个资源(这是 RESTful 吗?)

2)您不应该接受创建 ID 的客户(可以发布http://my.api.com/rest/Users/,而不是http://my.api.com/rest/Users/24)并且您不应该接受PUT 到不存在的资源。

编辑

所以我相信资源是由它的 URL 来标识的,而不是由 ID 来标识的。或者,换句话说,资源 ID 是http://my.api.com/rest/Users/23,而不是 23。

说得通?

于 2014-02-07T03:10:04.630 回答