I have trouble understanding why PATCH is not safe where PUT is. Aso the idempotent part - if I update a field of the resource, wouldn't that field return the same value after update?
Why PATCH is neither safe nor idempotent?
35.9k views Asked by Tony Vincent AtThere are 4 answers
First of all, PUT
isn't safe either.
Safe methods are HTTP methods that do not modify resources. For instance, using GET or HEAD on a resource URL, should NEVER change the resource.
Since PUT
request (so does PATCH for that matter) updates the resource, so it can't be cached and hence it's not SAFE.
PUT
request is idempotent though, or I should say PUT
request should be idempotent.
An idempotent HTTP method is a HTTP method that can be called many times without different outcomes. It would not matter if the method is called only once, or ten times over. The result should be the same. Again, this only applies to the result, not the resource itself. This still can be manipulated (like an update-timestamp, provided this information is not shared in the (current) resource representation.
The idea behind PUT
request being idempotent is that if an update call on a resource fails, a client can make the same call again without causing any undesirable or inconsistent state. PUT
request should always be preceded by a GET
request to the resource, and should succeed if and if only resource hasn't changed since. For elaboration:- go through one of the similar answer - Idempotent PUT request in concurrent environment
Now PATCH
request is intended to update just selective fields, it is not expected to GET the resource representation. So multiple calls to PATCH
request could end up in undesirable change in the resource state. Hence it is not IDEMPOTENT
.
For example:-
There is resource Person
Request 1: PATCH /person/1 {'age': 10} - updates the age of resource to 10
Now suppose some other parallel request changes the state of resource, say
Request 2: PATCH /person/1 {'age': 19} - updates the age of resource to 19
Now if sends the Request 1 again it would updates the resource age to 10 again, hence causing an undesirable result.
It can be made idempotent though using etags or If Modified Since headers.
I recently started looking if Patch is idempotent or not and after reading about the JSON patch format, i understood that if the add operation is applied using the Patch method its completely possible that the request is non-idempotent as it could add the new values to an existing resource if the same request is made multiple times.
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }
PATCH changes the resources attributes. The change may require a concrete previous value of the attribute, which makes it NON idempotent.
From Name=John to Name=Gargantua.
After repeated applying the name will be Gargantua and patch will fail, since it requires the name to be "John" before the change
"from Name=John"
It's not safe because in general you can't safely execute a PATCH request without changing a resource (That's what it's for).
So why is PATCH not idempotent compared to PUT? It's because it matters how you apply your changes. If you'd like to change the
name
property of a resource, you might send something like{"name": "foo"}
as a payload and that would indeed be idempotent since executing this request any number of times would yield the same result: The resourcesname
attribute is now "foo".But PATCH is much more general in how you can change a resource (check this definition on how to apply a JSON patch). It could also, for example, mean to move the resource and would look something like this:
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" }
. This operation is obviously not idempotent since calling at a second time would result in an error.So while most PATCH operations might be idempotent, there are some that aren't.
One remark on the other answers: Idempotence is defined by repeating an operation multiple times in a row. Saying that something is not idempotent because the effect is different if some other operation was executed in between or in parallel just isn't a valid argument (no operation would be idempotent in general if that was the case). Mathematically, an idempotent transformation is one that yields the same result, no matter how often you apply it (like rotating something 360 degrees). Of course two 360 deg rotation might yield different results if you apply any other operation in between.