75

I was wondering about this.

Suppose I have a user resource with id and name fields. If I want to update a field I could just do a PATCH request to the resource like this

PATCH /users/42
{"name": "john doe"} 

And then the application will update user 42 name.

But why if I repeat this request the outcome would be different?

According to RFC 5789

PATCH is neither safe nor idempotent

seldon
  • 1,002

4 Answers4

56

A PATCH request can be idempotent, but it isn't required to be. That is the reason it is characterized as non-idempotent.

Whether PATCH can be idempotent or not depends strongly on how the required changes are communicated.

For example, if the patch format is in the form of {change: 'Stock' add: -1}, then any PATCH request after the first one would have a different effect than the first request, i.e. a further decrease in the assumed stock of the product.

Another reason for non-idempotency can be that applying the modification on something else than the original resource can render the resource invalid. This would then also be the case if you apply the change multiple times.

Robert Harvey
  • 200,592
29

PATCH requests describe how to modify a resource, if you apply the same modification twice, the result may not be the same. This is because defining how the modifications are applied is up to you, you have to define the how to interpret the contents.

A PATCH request can be idempotent if you define it to be idempotent.

Idempotent example:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request { age: 33 }

// New resource { name: 'Tito', age: 33 }

Non-idempotent example:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request { $increment: 'age' }

// New resource { name: 'Tito', age: 33 }

A PATCH request can written in many formats, not just JSON.

In the second example I used a made up syntax for incrementing an attribute. Clearly this is not idempotent, as sending the same request again will result in different object.

Using such a made up syntax is valid according to standards:

The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version.

Whether it is restful to use PATCH requests this way is not clear, some people consider it is not, here's a good answer about the issue.

Jbm
  • 487
20

I think clear answer when PATCH in not idempotent is this paragraph from RFC 5789:

There are also cases where patch formats do not need to operate from a known base-point (e.g., appending text lines to log files, or non- colliding rows to database tables), in which case the same care in client requests is not needed.

As RFC specifies that patch contains some "general changes" to the resource, we should look beyond just typical field replacement. If resource is for a counter, then patch can request it's increment, which is clearly not idempotet.

Ivan
  • 301
0

GET is supposed to be idempotent. If I implement it on the server, and you rely on it being idempotent, but my implementation isn’t, it’s my fault.

PATCH is not guaranteed to be idempotent. So in the exact same situation, it’s your fault. Of course if I write the client code then I can publish that some specific operations are idempotent, and it would be useful to explain how other operations are not.

gnasher729
  • 49,096