Why PUT can’t be used for partial updates
I’ve been discussing PUT vs. PATCH with some colleagues and finally took the time to come up with a concrete example of why PUT absolutely should not be used for partial updates of resources. One colleague pointed out the following points made by Roy Fielding on the AtomPub listserv:
FWIW, PUT does not mean store. I must have repeated that a million times in webdav and related lists. HTTP defines the intended semantics of the communication — the expectations of each party. The protocol does not define how either side fulfills those expectations, and it makes damn sure it doesn’t prevent a server from having absolute authority over its own resources. Also, resources are known to change over time, so if a server accepts an invalid Atom entry via PUT one second and then immediately thereafter decides to change it to a valid entry for later GETs, life is grand.
Roy’s right, of course, but there is a subtlety that is easily overlooked. Sure, the server has the authority to “fix” the resource representation, for example, it might modify part of the resource representation passed in (i.e. if the client tries to modify the server controlled id property, the server can ignore that), but there is an important constraint that the server has to follow. PUT needs to be idempotent! This means the server can’t use the current state of the resource to “fix” the resource representation passed in. Have a look at the following simple example:
Let’s say that I have a resource that consists of a couple of properties, A and B, and I want to use PUT to support partial updates of this resource. The payload of the PUT will carry the properties that we wish to update; if a resource property is not present in the payload then that property will remain unchanged in the resource. We’re playing the “the server has control over what they do with the resource property” card. Check out the following sequence of operations then:
Ouch! The PUT is not idempotent! Client 1 does the same PUT twice, leaving the resource in two different states – one of which could very well be inconsistent. PUT semantics, when correctly followed, give the client the ability to control the consistency of the resource they are writing.
Hence RFC 5789 – PATCH Method for HTTP. PATCH does not have the constraint of being idempotent so the client cannot simply retry requests for which they never received a response. I do think it is interesting that RFC 5789 includes the following:
A PATCH request can be issued in such a way as to be idempotent, which also helps prevent bad outcomes from collisions between two PATCH requests on the same resource in a similar time frame. Collisions from multiple PATCH requests may be more dangerous than PUT collisions because some patch formats need to operate from a known base-point or else they will corrupt the resource. Clients using this kind of patch application SHOULD use a conditional request such that the request will fail if the resource has been updated since the client last accessed the resource. For example, the client can use a strong ETag [RFC2616] in an If-Match header on the PATCH request.
That is, you could make PATCH idempotent if you use the likes of ETags and conditional invocations. The same could be said for a PUT that does partial updates but the opportune world here is “could” – PUT is required to be idempotent even without the use of things such as ETags.
All of that said, while neither RFC 2616, nor RFC 5789 require the use of ETag like mechanisms, in most cases it’s a good idea.
anamaeka
Cornelia, why are you saying that the example with the two calls to put[A=10] is a breach of idempotence for PUT? It’s true that a resource or, in general, the state of the server-side system overall, is different after the 1st call to put[A=10] than it is after the 2nd call. But that doesn’t by itself imply a breach of idempotence. To demonstrate a breach, you would need a case where two changes to a state variable that came about as a result of each of the two calls to put[A=10] were changes leaving that state variable with two different values. But in your example, the variable A was updated to the same value by each call. Idempotence of a method doesn’t entail that there is no change in state to the system as a whole across two identical calls to the method. I’m probably missing something obvious. If you can follow up, I’d appreciate it.
Darrel Miller
I’m not convinced that your original example violates idempotency. The message being sent by the client is A=10. No matter how many times you send that request, the result is that A=10. By sending a partial update the client is making no assumptions about the other contents of the resource. The fact that other elements changed between the first and the second request does not change the client’s request or the effect of the client’s request.It is similar to the scenario of using a GET to retrieve a page with a counter on it. GET is safe, but two subsequent requests will return different results. This is considered acceptable because the client did not request the change and is not responsible for the change.In your scenario, the client requesting that A=10 made no statement about B and therefore cannot be held responsible for B changing. In the same way a server should be allowed to update a last modified time stamp on a document that is PUT.
joman
Your example isn’t very good. The retry on the PUT doesn’t do any harm. It’s setting A=10, and A is already 10 from the previous attempt. So there’s absolutely no harm done. A=10 and that is the intended result. You could set A=10 5 more times, and it still would be 10.I understand what you’re trying to say, it’s just not a good example to show your argument.
Cornelia Davis
OMG. Someone is reading. 🙂 So sorry to leave these comments in the queue for so long – I didn’t realized that I had any that weren’t spam…In any case, each of your comments make the same point, that I disagree with. Here’s the subtlety. “A” is not the resource here – the resource is the little blue box and it has two parts, A and B. The idempontency requirement is against the resource in its entirety, not against only a part of it. For PUT to be idempotent issuing one or more than one request will leave the _entire_ resource in the same state. The above example shows that if you do partial updates, that may not be the case. This is precisely why the Atom Publishing Protocol (http://www.ietf.org/rfc/rfc5023.txt) defines the editing of a resource to be a retrieval followed by a PUT where the entire resource representation is sent back to the server. Further, this is also the motivation for the standardization of PATCH (http://tools.ietf.org/html/rfc5789). PATCH is not expected to be idempotent.