为什么不允许HTTP PUT在REST API中进行部分更新?

时间:2013-11-01 17:52:46

标签: api http rest

谁说RESTful API必须通过HTTP PATCH分别支持部分更新?

似乎没有任何好处。它增加了在服务器端实现的更多工作,以及客户端的更多逻辑,以决定请求哪种更新。

我在使用HTTP创建REST API的上下文中提出这个问题,该API为已知数据模型提供抽象。要求PATCH进行部分更新,而不是PUT的全部或部分更新感觉它没有任何好处,但我可以被说服。

相关

http://restcookbook.com/HTTP%20Methods/idempotency/ - 这意味着您无法控制可能会缓存请求的服务器软件。

What's the justification behind disallowing partial PUT? - 没有给出明确答案,仅提及HTTP为PUt和PATCH定义的内容。

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/17415 - 显示了对此的分歧。

3 个答案:

答案 0 :(得分:53)

谁说?发明REST的人说:

  

@mnot Oy,是的,PATCH是我为初始HTTP / 1.1提案创建的,因为部分PUT从不是RESTful。 ; - )

https://twitter.com/fielding/status/275471320685367296

首先,REST是一种架构风格,其原则之一是利用其底层协议的标准化行为,因此如果您想通过HTTP实现RESTful API,则必须严格遵循HTTP它是RESTful的。如果你认为它不能满足你的需求,你可以不这样做,没有人会诅咒你,但是你不是在做REST。您必须记录偏离标准的位置和方式,在客户端和服务器实现之间建立强大的耦合,使用REST的全部目的正是为了避免这种情况并专注于您的媒体类型。

因此,基于RFC 7231,PUT应仅用于在幂等操作中完全替换表示。 PATCH应该用于部分更新,不需要是幂等的,但是通过在应用diff之前要求先决条件或验证当前状态来使它们成为幂等是一件好事。如果您需要进行非幂等更新(部分与否),请使用POST。简单。每个使用API​​的人都知道PUT和PATCH是如何工作的,他们希望它们以这种方式工作,而且您不必记录或解释方法应该对给定资源做什么。您可以自由地使PUT以您认为合适的任何其他方式行事,但是您必须为您的客户记录,并且您必须为您的API找到另一个流行语,因为这不是RESTful。

请记住,REST是一种专注于API长期演变的架构风格。要做到这一点现在添加更多工作,但以后会更容易更改,创伤更少。这并不意味着REST适用于所有人和每个人。如果您的重点是易于实施和短期使用,只需使用您想要的方法。如果您不想打扰客户选择正确的方法,您可以通过POST完成所有工作。

答案 1 :(得分:8)

要扩展the existing answerPUT应该执行资源状态的完全更新(覆盖),因为HTTP以这种方式定义了方法。 original RFC 2616 about HTTP/1.1对此并不十分明确,RFC 7231增加了语义澄清:

  

4.3.4 PUT

     

PUT方法请求创建目标资源的状态,或者用请求消息有效负载中包含的表示定义的状态替换目标资源的状态。给定表示的成功PUT将表明在相同目标资源上的后续GET将导致在200(OK)响应中发送等效表示。

如另一个答案中所述,遵守此约定简化了对API的理解和使用,并且无需明确记录PUT方法的行为。

但是,由于幂等性,不允许部分更新。我发现这很重要,因为这些概念经常被混淆,甚至在很多StackOverflow答案上都有用(例如here)。< / p>

Idempotent 仅表示一次或多次应用请求会对服务器产生相同的效果。再次引用RFC 7231:

  

4.2.2 Idempotent methods

     

请求方法被视为&#34;幂等&#34;如果使用该方法对服务器的多个相同请求的预期效果与单个此类请求的效果相同。

只要部分更新仅包含资源状态的新值并且不依赖于先前的值(即,那些值被覆盖),就满足了幂等性的要求。与应用此类部分更新的次数无关,服务器的状态将始终保持请求中指定的值。

来自其他客户端的中间请求是否可以更改资源的不同部分是不相关的,因为幂等性指的是操作(即PUT方法),而不是状态本身。并且对于部分覆盖更新的操作,其应用在应用一次或多次后产生相同的效果。

相反,非幂等的操作取决于当前服务器状态,因此根据执行的次数导致不同的结果。最简单的例子是递增一个数字(非幂等),而不是将其设置为绝对值(幂等)。

对于非幂等更改,HTTP预见方法POSTPATCH,而PATCH明确设计为对现有资源进行修改,而POST可以是关于请求URI,正文内容和服务器上的副作用的关系,可以更自由地解释。

这在实践中意味着什么? REST是通过HTTP协议实现API的范例 - 许多人认为这种惯例是合理的,因此很可能被采用或理解。仍然存在关于什么是RESTful以及什么不存在的争议,但即使不考虑这些,REST也不是构建HTTP API的唯一正确或有意义的方式。

HTTP协议本身会对您可能会和不会执行的操作施加约束,其中许多都会产生实际影响。例如,忽略幂等性可能导致缓存服务器改变客户端实际发出的请求数,并随后破坏应用程序所期望的逻辑。因此,在偏离标准时要注意其含义至关重要。

严格遵守REST,没有完全令人满意的部分更新解决方案(有些人甚至说这需要单独使用REST)。问题在于,PATCH首先看来只是为了这个目的,而不是幂等的。因此,通过使用PATCH进行幂等部分更新,您将失去idempotency的优势(任意数量的自动重试,更简单的逻辑,可能在客户端,服务器和网络中进行优化)。因此,您可能会问自己,使用PUT是否真的是最糟糕的想法,只要行为明确记录并且不会因为用户(和中间网络节点)依赖某些行为而中断... ?

答案 2 :(得分:-4)

PUT允许部分更新(根据RFC 7231 http://tools.ietf.org/html/rfc7231#section-4.3.4)。

“,... PUT请求被定义为替换目标资源的状态。” - 替换部分对象基本上改变了它的状态。

“通过定位具有与较大资源的一部分重叠的状态的单独标识的资源,可以进行部分内容更新,”

根据该RFC,下一个请求有效: PUT / resource / 123 {name:'new name'} 它将仅更改指定资源的名称。在请求有效负载内指定id将是不正确的(因为PUT不允许对未指定的资源进行部分更新)。

PS:以下是PATCH有用的示例。

有一个对象里面有Array。使用PUT,您无法更新特定值。您只能将整个列表替换为新列表。使用PATCH,您可以将一个值替换为另一个值。使用地图和更复杂的对象,效益会更大。