Why isn't HTTP PUT allowed to do partial updat

2020-02-16 08:40发布

问题:

Who says RESTful APIs must support partial updates separately via HTTP PATCH?

It seems to have no benefits. It adds more work to implement on the server side and more logic on the client side to decide which kind of update to request.

I am asking this question within the context of creating a REST API with HTTP that provides abstraction to known data models. Requiring PATCH for partial updates as opposed to PUT for full or partial feels like it has no benefit, but I could be persuaded.

Related

http://restcookbook.com/HTTP%20Methods/idempotency/ - this implies you don't have control over the server software that may cache requests.

What's the justification behind disallowing partial PUT? - no clear answer given, only reference to what HTTP defines for PUt vs PATCH.

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/17415 - shows the divide of thoughts on this.

回答1:

Who says? The guy who invented REST says:

@mnot Oy, yes, PATCH was something I created for the initial HTTP/1.1 proposal because partial PUT is never RESTful. ;-)

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

First of all, REST is an architectural style, and one of its principles is to leverage on the standardized behavior of the protocol underlying it, so if you want to implement a RESTful API over HTTP, you have to follow HTTP strictly for it to be RESTful. You're free to not do so if you think it's not adequate for your needs, nobody will curse you for that, but then you're not doing REST. You'll have to document where and how you deviate from the standard, creating a strong coupling between client and server implementations, and the whole point of using REST is precisely to avoid that and focus on your media types.

So, based on RFC 7231, PUT should be used only for complete replacement of a representation, in an idempotent operation. PATCH should be used for partial updates, that aren't required to be idempotent, but it's a good to make them idempotent by requiring a precondition or validating the current state before applying the diff. If you need to do non-idempotent updates, partial or not, use POST. Simple. Everyone using your API who knows how PUT and PATCH works expects them to work that way, and you don't have to document or explain what the methods should do for a given resource. You're free to make PUT act in any other way you see fit, but then you'll have to document that for your clients, and you'll have to find another buzzword for your API, because that's not RESTful.

Keep in mind that REST is an architectural style focused on long term evolution of your API. To do it right will add more work now, but will make changes easier and less traumatic later. That doesn't mean REST is adequate for everything and everyone. If your focus is the ease of implementation and short term usage, just use the methods as you want. You can do everything through POST if you don't want to bother about clients choosing the right methods.



回答2:

To extend on the existing answer, PUT is supposed to perform a complete update (overwrite) of the resource state simply because HTTP defines the method in this way. The original RFC 2616 about HTTP/1.1 is not very explicit about this, RFC 7231 adds semantic clarifications:

4.3.4 PUT

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response.

As stated in the other answer, adhering to this convention simplifies the understanding and usage of APIs, and there is no need to explicitly document the behavior of the PUT method.


However, partial updates are not disallowed because of idempotency. I find this important to highlight, as these concepts are often confused, even on many StackOverflow answers (e.g. here).

Idempotent solely means that applying a request one or many times results in the same effect on the server. To quote RFC 7231 once more:

4.2.2 Idempotent methods

A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.

As long as a partial update contains only new values of the resource state and does not depend on previous values (i.e. those values are overwritten), the requirement of idempotency is fulfilled. Independently of how many times such a partial update is applied, the server's state will always hold the values specified in the request.

Whether an intermediate request from another client can change a different part of the resource is not relevant, because idempotency refers to the operation (i.e. the PUT method), not the state itself. And with respect to the operation of a partial overwriting update, its application yields the same effect after being applied once or many times.

On the contrary, an operation that is not idempotent depends on the current server state, therefore it leads to different results depending on how many times it is executed. The easiest example for this is incrementing a number (non-idempotent) vs. setting it to an absolute value (idempotent).

For non-idempotent changes, HTTP foresees the methods POST and PATCH, whereas PATCH is explicitly designed to carry modifications to an existing resource, whereas POST can be interpreted much more freely regarding the relation of request URI, body content and side effects on the server.


What does this mean in practice? REST is a paradigma for implementing APIs over the HTTP protocol -- a convention that many people have considered reasonable and is thus likely to be adopted or understood. Still, there are controversies regarding what is RESTful and what isn't, but even leaving those aside, REST is not the only correct or meaningful way to build HTTP APIs.

The HTTP protocol itself puts constraints on what you may and may not do, and many of them have actual practical impact. For example, disregarding idempotency may result in cache servers changing the number of requests actually issued by the client, and subsequently disrupt the logic expected by applications. It is thus crucial to be aware of the implications when deviating from the standard.

Being strictly REST-conform, there is no completely satisfying solution for partial updates (some even say this need alone is against REST). The problem is that PATCH, which first appears to be made just for this purpose, is not idempotent. Thus, by using PATCH for idempotent partial updates, you lose the advantages of idempotency (arbitrary number of automatic retries, simpler logic, potential for optimizations in client, server and network). As such, you may ask yourself if using PUT is really the worst idea, as long as the behavior is clearly documented and doesn't break because users (and intermediate network nodes) rely on certain behavior...?



回答3:

Partial updates are allowed by PUT (according to RFC 7231 http://tools.ietf.org/html/rfc7231#section-4.3.4).

",... PUT request is defined as replacing the state of the target resource." - replacing part of object basically change state of it.

"Partial content updates are possible by targeting a separately identified resource with state that overlaps a portion of the larger resource, ..."

According to that RFC next request is valid: PUT /resource/123 {name: 'new name'} It will change only name for specified resource. Specifying id inside request payload would be incorrect (as PUT not allow partial updates for unspecified resources).

PS: Below is example when PATCH is useful.

There is object that have Array inside. With PUT you can't update specific value. You only could replace whole list to new one. With PATCH, you could replace one value to another. With maps and more complex objects benefit will be even bigger.



标签: api http rest