RESTful资源 - 接受对象列表

时间:2010-07-07 21:47:31

标签: rest

我正在构建一个RESTful资源集合,其工作方式如下:(我将以“people”为例):

    GET /people/{key}
      - returns a person object (JSON)
    GET /people?first_name=Bob
      - returns a list of person objects who's "first_name" is "Bob" (JSON)
    PUT /people/{key}
      - expects a person object in the payload (JSON), updates the person in the 
        datastore with the {key} found in the URL parameter to match the payload.
        If it is a new object, the client specifies the key of the new object.

到目前为止,我对设计感到非常满意(尽管欢迎任何输入/批评)。

我也希望能够列出一个人的列表,但是我对我的设计的RESTful不满信心。这就是我的想法:

    PUT /people
      - expects a list of objects in JSON form with keys included in the object
        ("key":"32948").  Updates all of the corresponding objects in the datastore.

此操作将是幂等的,因此我想使用“PUT”。但是它违反了规则,因为对同一资源的GET请求不会返回客户端只是PUT的等价物,而是返回所有“人”对象(因为查询上没有过滤器)。我怀疑还有一些其他规则可能会被打破。

有人提到在我之前的问题中使用了“PATCH”请求:REST resource with a List property

“PATCH”听起来很棒,但我不想使用它,因为它尚未广泛使用,并且与许多程序和API不兼容。

我不想使用POST,因为POST意味着请求不是幂等的。

有没有人有任何意见/建议?

后续:::

虽然我对使用POST犹豫不决,因为它似乎是最不常见的分母,RESTful操作的全部内容以及关于此操作的更多内容(特别是它是幂等的),PUT因其要求而无法使用太狭隘了。具体来说:资源未完全重写,并且等效资源未从GET请求发送回同一资源。当应用程序,API和/或程序员尝试使用资源并且遇到来自资源的意外行为时,使用具有其规范之外的属性的PUT可能会导致问题。

除了接受的答案之外,如果操作绝对必须是PUT并且将UUID附加到资源路径的末尾,那么Darrel Miller有一个很好的建议,因此等效的GET请求将返回等效资源。

4 个答案:

答案 0 :(得分:8)

POST表示除GETPUTDELETE以外的通用操作(通用哈希表操作)。由于通用散列表操作不合适,因此请使用POSTPOST的语义由实体POST编辑的资源决定。这与通用散列表方法的语义不同,后者是众所周知的。

POST /people/add-many HTTP/1.1
Host: example.com
Content-Type: application/json

[
  { "name": "Bob" },
  { "name": "Robert" }
]

答案 1 :(得分:3)

在这种情况下,使用PUT绝对是错误的动词。 POST意味着完全按照你的要求去做。来自HTTP specification

  

POST和PUT请求之间的根本区别体现在Request-URI的不同含义上。 POST请求中的URI标识将处理所包含实体的资源。该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体。相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,服务器不得尝试将请求应用于其他资源...

因此,如果您想在一次通话中更新多个资源, 就可以使用POST。

只是因为PUT需要是幂等的而POST不是,并不意味着POST不能是幂等的。您选择的HTTP谓词不应基于此,而应基于所请求资源与所采取资源的关系。如果您的应用程序直接处理请求的资源,请使用PUT。如果它作用于某些其他资源(或资源,如您的情况),请使用POST。

答案 2 :(得分:2)

我真的没有看到任何简单的方法可以使用PUT来创建任意一组人。除非,您准备让客户端生成GUID并执行类似的操作,

PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}

在服务器端,您可以从列表中选择人员并将其添加到/People资源。

这种方法的一个细微变化是让服务器包含诸如

之类的链接
<link rel="AddList" href="/PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}"/>
人力资源中的

。客户需要知道它需要将人员列表输入AddList链接。服务器需要确保每次呈现/ People资源时,它都会为AddList链接创建一个新URL。

答案 3 :(得分:0)

关于Darren Miller建议将PUT用于GUID(我无法评论......),使用PUT的目的是为了实现操作的幂等性。如果幂等性将是客户端和服务器之间的对话,那么试金石是

  1. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
  2. 204 NO CONTENT(表示一切顺利)
  3. 客户端失去连接但看不到204
  4. 客户端自动重试
  5. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
  6. 服务器如何区分这两者?如果GUID“已用完”,那么服务器必须回复404410。这在服务器上引入了一小部分会话状态,以记住所有已使用的GUID。

    两个客户经常会看到相同的,因为缓存或只是保持陈旧的响应。

    我认为一个聪明的解决方案是使用POST为您可以PUT的资源创建一个(最初空的,短暂的)保留区域,即客户端需要POST来创建GUID资源而不是通过链接发现它:

    1. POST /PeopleList/CreateHoldingArea
    2. 201 CREATEDLocation: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
    3. PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
    4. 这意味着失去的幂等性不会带来太大的开销;如果客户端没有看到初始201 CREATED响应,则只需创建新的GUID(通过POST)。 “微小的会话状态”现在只是创建但尚未使用的保留区域。

      理想的解决方案当然不需要服务器上的任何会话状态,但它让我望而却步。