我正在构建一个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请求将返回等效资源。
答案 0 :(得分:8)
POST
表示除GET
,PUT
和DELETE
以外的通用操作(通用哈希表操作)。由于通用散列表操作不合适,因此请使用POST
。 POST
的语义由实体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的目的是为了实现操作的幂等性。如果幂等性将是客户端和服务器之间的对话,那么试金石是
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
204 NO CONTENT
(表示一切顺利)204
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
服务器如何区分这两者?如果GUID“已用完”,那么服务器必须回复404
或410
。这在服务器上引入了一小部分会话状态,以记住所有已使用的GUID。
两个客户经常会看到相同的,因为缓存或只是保持陈旧的响应。
我认为一个聪明的解决方案是使用POST为您可以PUT的资源创建一个(最初空的,短暂的)保留区域,即客户端需要POST来创建GUID资源而不是通过链接发现它:
POST /PeopleList/CreateHoldingArea
201 CREATED
和Location: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
这意味着失去的幂等性不会带来太大的开销;如果客户端没有看到初始201 CREATED
响应,则只需创建新的GUID(通过POST)。 “微小的会话状态”现在只是创建但尚未使用的保留区域。
理想的解决方案当然不需要服务器上的任何会话状态,但它让我望而却步。