REST API PATCH或PUT

jav*_*eek 252 rest http http-put http-method http-patch

我想用以下场景的适当方法设计我的休息端点.

有一个小组.每个组都有一个状态.管理员可以激活或取消激活该组.

我应该将我的终点设计为

PUT /groups/api/v1/groups/{group id}/status/activate
Run Code Online (Sandbox Code Playgroud)

要么

PATCH /groups/api/v1/groups/{group id}

with request body like 
{action:activate|deactivate}
Run Code Online (Sandbox Code Playgroud)

Luk*_*son 299

PATCH在您更新现有资源(组ID)时,此方法是正确的选择. PUT只应在您完全替换资源时使用.

有关部分资源修改的更多信息,请参见RFC 5789.具体地,该PUT方法描述如下:

扩展超文本传输​​协议(HTTP)的几个应用程序需要一个功能来进行部分资源修改.现有的HTTP PUT方法仅允许完全替换文档.此提议添加了一个新的HTTP方法PATCH来修改现有的HTTP资源.

  • 值得注意的是,RFC 5789仍处于提案阶段,尚未被正式接受,目前被标记为"irrata exists".这种"最佳实践"备受争议,技术上PATCH还不是HTTP标准的一部分. (33认同)
  • 几年之后只需2美分:您可以将状态本身视为资源,如果是这样,使用PUT对/ status在技术上将替换该端点的状态资源. (4认同)
  • 我敢于反对文档,即使它是"RFC".文档声明您应该使用PATCH来仅修改资源的一部分,但它忽略了PATCH方法被定义为非幂等方法的重要事项.为什么?如果PUT方法是在考虑整个资源的更新/替换的情况下创建的,那么为什么不将PATCH方法创建为像PUT这样的幂等方法,如果它的目的只是更新资源的一部分?对我而言,它更像是更新的幂等性,例如"a = 5"(PUT)和"a = a + 5"(PATCH).两者都可以更新整个资源. (2认同)

ber*_*kes 166

REST中的R代表资源

(事实并非如此,因为它代表Representational,但它是记住REST在REST中的重要性的一个好方法).

关于PUT /groups/api/v1/groups/{group id}/status/activate:您没有更新"激活"."激活"不是一个东西,它是一个动词.动词永远不是好资源.根据经验:如果动作(动词)在URL中,则可能不是RESTful.

你做什么呢?您要么"添加","删除"或"更新" 群组上的激活,要么您更喜欢:在群组上操纵"状态" - 资源.就个人而言,我会使用"激活",因为它们比"状态"概念更不明确:创建状态是模糊的,创建激活不是.

  • POST /groups/{group id}/activation 创建(或请求创建)激活.
  • PATCH /groups/{group id}/activation更新现有激活的一些细节.由于一个组只有一个激活,我们知道我们所指的激活资源.
  • PUT /groups/{group id}/activation插入或替换旧的激活.由于一个组只有一个激活,我们知道我们所指的激活资源.
  • DELETE /groups/{group id}/activation 将取消或删除激活.

当组的"激活"具有副作用时,例如正在进行付款,发送邮件等,此模式非常有用.只有POST和PATCH可能会产生这样的副作用.例如,当删除激活需要通过邮件通知用户时,DELETE不是正确的选择; 在这种情况下,您可能想要创建一个停用资源:POST /groups/{group_id}/deactivation.

遵循这些指导原则是一个好主意,因为这个标准合同使您的客户以及客户端和您之间的所有代理和层,在重试安全时,以及何时不重复时都非常清楚.假设客户端在某个地方有片状wifi,并且用户点击"deactive",这会触发DELETE:如果失败,客户端可以简单地重试,直到它获得404,200或其他任何可以处理的内容.但如果它触发了POST to deactivation它知道不重试:POST意味着这一点.
任何客户现在都有合同,如果遵循该合同,将防止发送42封电子邮件"您的群组已被停用",原因很简单,因为其HTTP库不断重试对后端的调用.

更新单个属性:使用PATCH

PATCH /groups/{group id}

如果您想更新属性.例如,"status"可以是可以设置的Groups的属性.诸如"状态"之类的属性通常是限制值列入白名单的良好候选者.示例使用一些未定义的JSON方案:

PATCH /groups/{group id} { "attributes": { "status": "active" } }
response: 200 OK

PATCH /groups/{group id} { "attributes": { "status": "deleted" } }
response: 406 Not Acceptable
Run Code Online (Sandbox Code Playgroud)

更换资源,没有副作用使用PUT.

PUT /groups/{group id}

如果您想要更换整个集团.这并不一定意味着服务器实际上创建了一个新组并抛出旧组,例如,ID可能保持不变.但对于客户来说,这是什么PUT 意味着:客户应承担他得到了一个全新的项目,基于服务器的响应.

PUT请求的情况下,客户端应始终发送整个资源,包含创建新项目所需的所有数据:通常需要与POST-create相同的数据.

PUT /groups/{group id} { "attributes": { "status": "active" } }
response: 406 Not Acceptable

PUT /groups/{group id} { "attributes": { "name": .... etc. "status": "active" } }
response: 201 Created or 200 OK, depending on whether we made a new one.
Run Code Online (Sandbox Code Playgroud)

一个非常重要的要求是PUT幂等:如果在更新组(或更改激活)时需要副作用,则应使用PATCH.因此,当更新导致例如发送邮件时,请不要使用PUT.

  • 这对我来说非常有用."当一个群体的"激活"产生副作用时,这种模式很有用" - 这个模式怎么会有用,特别是关于动作何时产生副作用,而不是OP初始端点 (2认同)
  • @Abdul,该模式出于多种原因很有用,但考虑到副作用,客户应该非常清楚某个操作会产生什么影响。例如,当 iOS 应用程序决定将整个地址簿作为“联系人”发送时,应该非常清楚联系人的创建、更新、删除等操作会产生哪些副作用。例如,为了避免向所有联系人群发邮件。 (2认同)
  • 非常有帮助的答案。谢谢!我还要添加一条评论,就像在 Luke 的回答中一样,指出 PUT/PATCH 之间的区别不仅仅是整体/部分更新,还有不同的幂等性。这不是一个错误,这是一个有意的决定,我认为在决定 HTTP 方法的使用时,没有多少人考虑到这一点。 (2认同)
  • 我同意和不同意。RESTful API 不应反映您的域。他们更倾向于对应用程序的用例进行建模,而不是对业务进行建模。RESTful api 遵循 RFC 2616 是有原因的。作为消费者,我不知道您的业务运营的“副作用”是什么。我所知道的是,您的 HTTP 动词应该反映对资源的操作。因此,如果 DELETE 是幂等的,则意味着对 RESOURCE 的操作也是幂等的。不是“副作用”。发送电子邮件并不违反“幂等性”。这是一个业务问题,而不是 RESTful API。 (2认同)

Clo*_*ist 12

我建议使用PATCH,因为您的资源"组"有很多属性,但在这种情况下,您只更新激活字段(部分修改)

根据RFC5789(https://tools.ietf.org/html/rfc5789)

现有的HTTP PUT方法仅允许完全替换文档.此提议添加了一个新的HTTP方法PATCH来修改现有的HTTP资源.

另外,更多细节,

PUT和PATCH请求之间的差异反映在服务器处理封闭实体以修改
Request-URI标识的资源的方式中.在PUT请求,封闭的实体被认为是存储在对资源的修改版本
源服务器和客户端的请求存储的版本
替换.补丁,但是,封闭的实体包含了一组描述如何目前居住在资源上的说明
原始服务器应该进行修改,以产生一个新的版本.PATCH方法影响Request-URI标识的资源,它
也可能对其他资源产生副作用; 即,
可以通过应用
PATCH 来创建新资源,或者修改现有资源.

PATCH既不是[RFC2616]第9.1节定义的安全也不是幂等的.

客户端需要选择何时使用PATCH而不是PUT.对于
例如,如果补丁文件大小比大小大
,将在PUT中使用新的资源数据,那么它可能是
有意义的使用PUT而不是补丁.要发布一个比较更是难上加难,因为POST在广泛不同的方式使用,并且能够
在服务器选择包括PUT和PATCH般的操作.如果
操作不以可预测的方式修改Request-URI标识的资源,则应考虑POST而不是PATCH
或PUT.

PATCH的响应代码是

使用204响应代码是因为响应没有携带消息体(具有200代码的响应将具有).请注意,也可以使用其他成功代码.

也请参考http://restcookbook.com/HTTP%20Methods/patch/

警告:实现PATCH的API必须以原子方式进行修补.当GET请求时,不可能对资源进行半修补.


And*_*ski 7

由于您希望使用REST架构样式设计API,因此需要考虑用例来确定哪些概念足以作为资源公开.如果您决定将组的状态公开为子资源,您可以为其提供以下URI并实现对GET和PUT方法的支持:

/groups/api/groups/{group id}/status
Run Code Online (Sandbox Code Playgroud)

这种方法相对于PATCH进行修改的缺点是,您无法以原子方式和事务方式对组中的多个属性进行更改.如果事务更改很重要,请使用PATCH.

如果您决定将状态公开为组的子资源,则它应该是组表示中的链接.例如,如果代理获得组123并接受XML,则响应主体可以包含:

<group id="123">
  <status>Active</status>
  <link rel="/linkrels/groups/status" uri="/groups/api/groups/123/status"/>
  ...
</group>
Run Code Online (Sandbox Code Playgroud)

需要一个超链接来实现超媒体作为 REST架构风格的应用程序状态条件的引擎.