RESTful GET响应是否应该返回资源的ID?

时间:2012-07-02 18:42:58

标签: json api rest restful-architecture data-consistency

此处的一些开发人员正在就 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的形状,并影响几个开发人员在新的几周内的工作量。

2 个答案:

答案 0 :(得分:15)

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

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

你提出的关于收藏的观点非常重要。为retrieve-1操作使用一个表示是否有意义,以及retrieve-N操作的另一个表示是否有意义?我想不是。

但是,您遇到的问题更为一般 - 应该在转移到客户端的表示中包含哪些数据,以及在什么情况下?在某些情况下调用者根本不关心属性的重要子集。特别是在检索到大量对象的情况下 - 与基本通信成本相比,传输数据的成本更高 - 您希望优化发回的内容。

所有足够成熟的REST协议都能够对返回的数据进行整形。

例如,见

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

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

enter image description here

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

您可以在https://api.stackexchange.com/docs/answers

看到这一点

...并且具体参见过滤器规格对话框。

enter image description here


没有一种正确的做事方式。你需要平衡"塑造"的复杂性。您支持开发成本和将使用API​​的应用程序的需求。

答案 1 :(得分:2)

老问题,但是因为我到这里寻找一些东西,这里又有另一种意见:

首先,我认为网址应为:

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

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

“GET”位于HTTP方法上,而不是URL上。它只是命名,但有助于使事情更清晰,恕我直言。

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

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

在这种情况下,客户端需要跟踪URL,而不是ID。资源是否返回ID字段无关紧要。客户需要保留从中获取的地图。

如果您尝试将重新分配到其他网址,例如“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。

有道理吗?