Search code examples
resthttpapi-design

Http idempotent partial modifications of a resource are better of implemented as PUT instead of PATCH?


Http PATCH method is considered non idempotent and applies partial modifications to a resource ,

in contrast of PUT which is idempotent and applies a replacement of a resource.

(as MDN states) :

The HTTP PATCH request method applies partial modifications to a resource.

The HTTP PUT method only allows complete replacement of a document. Unlike PUT, PATCH is not idempotent, meaning successive identical patch requests may have different effects.

But it is possible to implement PATCH in an idempotent manner (MDN) :

However, it is possible to issue PATCH requests in such a way as to be idempotent.

an example of an idempotent implementation of patch is :

path: /contact/:id
method: patch
body {
name: 'John'
}

no matter the number of times this request will be made - the resource will remain in the same state as after the first request.

since idempotent request gets optimized (reference):

Clients may automatically cancel a GET request if it is taking too long to process and repeat it because they assume it has the same effect (since GET is idempotent). However, they won’t do the same thing for POST requests because the first one may have already altered some state on the server side.

As i understand this optimization can be applied only to http methods that are considered idempotent by the HTTP standard.

Therefore the idempotent PATCH request i wrote above will not be optimized. (as i understand HTTP standard states that patch is non idempotent - but does not forbid it to be implemented as idempotent).

Since PUT is considered idempotent by HTTP standard. Isn't it preferred to use the /contact/:id PATCH request to be a PUT (in order to gain the optimization mentioned above ) ?

UPDATE 1


i can modify the request to be a PUT and implement it in the server in a way that it will only update the properties which were sent in the payload of the request, and ignore properties which were not sent. in that way i'm doing a PUT request which modifies parts of the resource in an idempotent manner that will be optimized, and i'm not replacing the entire resource. event if the resource is very large and the change i want to make is very small , if its implemented in an idempotent manner isn't it better to use PUT every time ?

that brings me to the title : idempotent partial modifications of a resource are better of implemented as PUT instead of PATCH ?


UPDATE 2 :


As stated in this question answers: 1 , 2

The reason for HTTP idempotent partial modifications are not better implemented as PUT is : It defies the REST architectural design

some of the disadvantages that comes with this are :

  1. other programmers will not understand the Partial updating PUT , and further documentation regarding that endpoint should be written.

  2. Will not be able to GET the exact resource that was sent in the previous "partial updating PUT".

  3. since REST is focused on the long term evolution of our API, adhering to it might save us time in the future.

and probably there are a lot more of disadvantages of not adhering to the REST architectural style...

but if we look at this from a performance point of view , if the request is idempotent the Partial PUT update is better (since it gets the optimization mentioned above).

i would be happy to hear of some more reasons that comes to mind :) .

Thanks


Solution

  • as i understand HTTP standard states that patch is non idempotent - but does not forbid it to be implemented as idempotent

    That is correct. It's a bit more precise to say that the standard doesn't guarantee idempotent semantics.

    idempotent partial modifications of a resource are better of implemented as PUT instead of PATCH ?

    "It depends".

    Yes, you are right that if PUT is used, then generic components will be able to recognize that the server promises idempotent handling of the request, and therefore it will be safe to automatically resend the message (for instance, if we time out waiting for the response to arrive).

    You don't get that same behavior with PATCH, because the intermediaries would need to understand the patch document media type, and go digging through the request payload trying to figure out what is going on.

    But... there is no such thing as "partial PUT". If the desired representation of the resource is very large, and the change that you want to make is very small, then sending a patch document, rather than the complete representation, can make a lot of sense.

    The choice comes down to a trade off of concerns - which of the problems that you have are most important, and which can be dismissed.

    why there is not such thing a partial PUT ?

    Because the HTTP semantics don't define it that way. RFC 7231

    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.

    PUT doesn't mean "apply idempotent handling to this request". It means replace; something analogous to overwrite file on a file system or set of a variable.

    Keep in mind that uniform interface is one of the REST constraints - it's what allows us to use generic components to communicate in a standard way.

    If you wanted idempotent partial replacement, adhering to the REST constraints, then what you would do is create a specification for a new method. There's a well defined process, and a registry where you can look up the standards for methods that have been through the process.

    Having defined the method, component providers can decide whether or not to opt in and support your new standard.

    Expressing the idea another way: in a situation where you control the client and the server, there's nothing wrong with embedding custom semantics into the messages. But if you are going to do that with one the standard method types, then you should use POST -- because that's the method where generic components will make the fewest assumptions about what is going on.