Ask HN: At this point, are PUT and PATCH helpful?
EDIT: Thanks for the input fellow beings. I really appreciate it. I think I have a much better idea of what people feel/do and why... so I'm going on a walk now to think it around.
---------------------
I'm designing an API, and trying to place PUT and PATCH into my design ideology.
In my experience, most APIs stick to GET and POST almost exclusively. And AFAICT, PUT and PATCH don't really add much that POST doesn't have. In fact, I kind of prefer the idea of having the url tell me what's going on explicitly rather than trying to infer from the request type. For example:
- to create: `POST user`
- to update: `POST user/12354`
vs
- to create: `POST user/`
- to update: `PATCH user/`
--------
I'm working alone on this project, otherwise I'd ask a coworker, but what do you guys think? What feels intuitive and clear to you?
49 comments
[ 2.7 ms ] story [ 141 ms ] threadI was recently working with the Vultr API, and they follow this pattern as well: https://www.vultr.com/api/#section/Introduction
It's like when someone has big ideas about how things are gonna go, but then reality ends up taking some other opportunity path.
I also created an associated library/spec json-patch-rules[2]
If you're using Mongoose ORM, I made mongoose-patcher[3].
When coupled with fast-json-patch[4] and clone/deep compare on the client, these technologies can make your life really easy.
[1] - http://jsonpatch.com/
[2] - https://github.com/claytongulick/json-patch-rules
[3] - https://github.com/claytongulick/mongoose-json-patch
[4] - https://github.com/Starcounter-Jack/JSON-Patch
Yes, it matters. You're misusing POST in the first example.
C = POST R = GET U = PUT/PATCH D = DELETE
Doing anything else is an anti-pattern for interop on the web.
They're usually a case of a ["desire path"](https://miro.medium.com/max/2592/0%2AD1R7QvewXmwUVytD.)
Typically, it says more to me about the designer than the users.
If you misuse POST nobody and nothing is going to care. Literally every traditional web application, including this very site, "misuses" POST all the time.
Around me I cannot name one backend developer who will design an API with POST used for update. We did it in the past when browsers where not implementing PUT or PATCH but still sending method=PUT/PATCH as param.
Of course this is my experience and I might be in a bubble.
That said, PUT and PATCH can be quite useful if you're dealing with CRUD operations. If you want or need your API to be idempotent, use POST for creation and updating. If being idempotent isn't a requirement - or even a negative - then adhere to the convention: POST for creation and PUT/PATCH for update.
PATCH is really nice to support when your objects are even moderately large or you want to reduce bandwidth costs. For example, let's say you have a user object in a NoSQL DB and each user is a JSON object with 100 keys. If you use POST or PUT to update, you're basically requiring that the user of your API...
* Perform a GET to actually fetch the entire user object * POST/PUT the entire object back with the changes
In addition, you're likely going to want the API to track the version of the object, otherwise you run into issues with multiple clients trying to update at the same time. This can be very problematic when updating the entire object. So you're basically wasting cycles on the server fetching data, wasting bandwidth for data that isn't going to be used at all, and possibly writing extra code to handle conflicts.
With PATCH, you don't need to GET anything. You can update fields pretty easily w/o even knowing what's already there:
PATCH /user/12345 { "age": 10 }
Very little bandwidth is used. If you still need versioning along with that (yes, you do if this is more than a pet project) to resolve conflicts, then you can use a HEAD request for the user and return the version of the object in an HTTP header. Multiple patches from different versions can all be successfully applied on top of each other until a conflict arises. But, then you're getting into vector clocks or other solutions that are outside the scope of the question.
Circling back, yes, PUT and PATCH can be very useful. ;)
HTH
PATCH /user/12345 { "age": 10 }
and
POST /user/12345 { "age": 10 }
to be the same function for an API which doesn't allow users to assign ids.
And thank you for your thorough answer.
Typical rest usage has POST creating new objects, and return the object with a new id. That's not idempotent. Doing it repeatedly makes new objects with new unique IDs. PUT is updating a given object, with the id in the URL. If you do it repeatedly, it's the same as a one time call.
POST /user --> returns user with id
PUT /user/12345 --> stores the data in the body for user with id 12345
PATCH /user/12345 --> merges the body with the existing object that has id 12345. (used to update specific field or fields)
This bit is wrong.
First, implementing idempotence for your endpoint is UP TO YOU, no matter what method you use. For some methods (though not POST), idempotence is a requirement for spec compliance, not a thing HTTP somehow magically gives you.
Second, although some methods (notably PUT and DELETE) are required to be idempotent (though that's really kind of a freebie when you read the rest of the requirements for those methods), you're welcome to implement idempotent endpoints behind a POST.
> If you use POST or PUT to update...
You're correct about PUT, but POST has no such requirement. You can send anything you want in a POST, because you may legally define whatever semantics you want on the fictitious purpose of the entity you're including.
Circling back, PUT and PATCH give no advantages over POST. :)
The concept of "patching" records and the http verb patch don't need to be linked. You could setup POST /user/12345/update to do what you described.
If you prefer more of a one query or request to rule them all then GraphQL may align better to your preferences.
If it really needs to be everywhere, you'll probably need to accept GET as well.
You also need to do your own work to make things idempotent if it matters. Your client won't know if the server saw and processed the request if the client didn't get the response, so it's likely to retry.
There will never be a buzzword that replaces the neccesisty of good program design.
There are some reasonable arguments that different verbs can/should indicate idempotence or hint at what the response might be, but it's useless in practice because almost no one follows the spec.
1. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Also, most modern SAAS services have APIs that follow this de facto standard.
My contention is that some common design patterns are violating the HTTP spec by using POST instead of PUT or PATCH.
That's fine -- I don't care and don't conform to the HTTP or REST specs myself. My original point is that these distinctions are not some hipster invention, but rather part of the original specs themselves.
From the link I posted:
> "The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request."
The way this plays out in the modern CRUD world is as simple as:
POST = "create a new entity" (no ID provided)
PUT = "replace an existing entity with this new one" (ID provided for an existing entity)
PATCH = "update an existing entity with these new values" (ID provided for an existing entity)
The spec is clear that POST, PUT, and PATCH do different things, and it is explicit that they be used as described ("MUST" and "MUST NOT" rather than "SHOULD" and "SHOULD NOT").
I do care about conformance with the HTTP specs. REST doesn't even have a spec, so saying you don't conform to the REST specs is... uh... weird.
As per your on-point quotation, the semantics of POST are "please handle this". It's the super-vague catch-all, you can use a POST for any "data-accepting process", or things with semantics as general as "a gateway to some other protocol". It's never spec-violating to use POST, POST is the method that makes no commitments.
On the other hand, PUT and DELETE have clear semantic limits, and PATCH more-or-less does.
As such, there will be situations where PUT and POST are both conformant, situations where PATCH and POST are both conformant, situations where DELETE and POST are both conformant, but no situations where POST is not conformant.
> The way this plays out in the modern CRUD world is...
Ugh, no. That's the hipster invention. (It's also only modern if you think 2005 is modern, or maybe some earlier date.) The hipster convention is an okay-ish convention, as good as any other cookie-cutter, so I guess if you don't have time to actually pay attention to the implications of the spec I guess you can do worse than teach your juniors to create with POST and update with PUT. But it's not the one way to do it, not the right way to do it, not the only REST-as-in-Fielding-compliant way to do it... it's just the way Rails did it (and maybe some prior framework, I don't know).
POST is perfectly okay for updating, modifying, deleting, or anything. POST is analogous to a procedure call... it can do anything.
PUT is for setting resources to entities, which yes includes overwriting, but also includes assigning to a previously-unused URL. PUT is analogous to variable assignment in imperative languages like Pascal; it may not modify anything but the resource designated by the request URL.
> The spec is clear that POST, PUT, and PATCH do different things, and it is explicit that they be used as described ("MUST" and "MUST NOT" rather than "SHOULD" and "SHOULD NOT").
I, too, think that the spec is pretty clear, but I think you've mis-read it, so maybe it's not so clear. As per my previous question, *where does the spec obligate the conscientious endpoint designer to use PUT?* That is, if you find yourself in a situation where PUT is legal, what bit of the spec says that you MUST NOT use POST instead?
I see no way of interpreting the spec as saying using POST to send messages to an api endpoint for processung instead of some specific method, is less correct than using a more specific method.
The HTTP spec refers to these "files" as resources, which it sometimes also calls "data".
All persistent data on a server is a file ultimately, whether it's part of a database or not, so I'm not sure what your point is. Nearly all useful APIs will interact with files.
> If you do that against an api, then the behaviour is to edit the source code of the api (WebDav interpretation)
What? Absolutely not. I have no idea how you made this leap. WebDAV is just a specific HTTP spec that involves content. There is nothing in the HTTP spec that relates to editing source files.
> I see no way of interpreting the spec as saying using POST to send messages to an api endpoint for processung instead of some specific method, is less correct than using a more specific method.
I don't either. That's not at all what I was contending.
Here's what the spec clearly says about the difference between POST and PUT:
> "The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request."
I agree with other commenters that the whole thing is rather silly.
Forcing callers to send a PUT with the whole user profile object every time someone updates a single thing is pretty wasteful.
+ if a caller is a caller that listens to events like "user u wants to update their number to 555 555 555, please do that", they don't even have the whole user object, they'd have to make a GET first, then set the new number, then send that whole PUT. That in turn introduces race conditions where their PUT could overwrite some other change someone else made to eg the email address in the meantime.
So there's definitely a case for PATCH! It all depends on your use case. For many systems it might not be something that's an issue.
But you seem like a thoughtful person, so maybe use CAREFULLY. To indicate to clients that they should handle data with love and attention to formatting.
:)
GET and POST should cover most of your bases. I like PUT and PATCH, too. I think you should use them when you want to keep your HTTP API nice and neat, because they provide useful intuitive signals to developers. Remember, as others have mentioned here, not all clients have the ability to send those verbs, so provide a way to override POST.
Oh, and sort of unrelated, not sure if you need to read this, but just in case you get to feeling playful, keep in mind that WebDAV verbs are for WebDAV. Not that you've mentioned anything WebDAV related, but I've noticed some developers who ask questions like this end up reading the relevant RFCs and start thinking to themselves, "...well what if I..."
https://bugs.php.net/bug.php?id=55815
Show all comments: GET api/comments
Create a comment: POST api/comment/
Show a comment: GET api/comment/1234
Edit the whole comment: PUT api/comment/1234
Edit part of the comment (like an attachment): PATCH api/comment/1234
Delete: DELETE api/comment/1234
i.e. use POST to create new things and PUT and/or PATCH to change existing things.
I've never seen PATCH [2] used effectively. I would expect a PATCH request body to be a diff of an existing file which is retrievable with GET. Optimizations are not worthwhile for most projects.
Most APIs do not store binary blobs. Most APIs operate on complicated sets of database tables and should use POST, GET, and maybe DELETE.
[0] https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PU...
[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
[2] https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PA...
https://blog.atomist.com/kubernetes-apply-replace-patch/
The standard way to implement optimistic concurrency with HTTP REST APIs is using the If-Match header [2]. The Kubernetes authors chose to use a 'resourceVersion' query parameter instead [0].
Kubernetes Team decided to implement *three* different kinds of patches: JSON patch, JSON merge patch, and strategic merge patch.
Kubernetes Team also chose to put 1,500 pages of docs on a single page, making searching extremely difficult or impossible. Bazel team [3] and Flutter team [4] also make their docs difficult to search.
Kubernete's Patch implementation may be technically correct, but it has a lot of usability problems, which translate into wasted engineering effort maintaining integrations with it.
[0] https://kubernetes.io/docs/reference/generated/kubernetes-ap...
[1] https://kubernetes.io/docs/tasks/manage-kubernetes-objects/u...
[2] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If...
[3] https://docs.bazel.build/versions/main/command-line-referenc...
[4] https://github.com/flutter/flutter/issues/80849
SPARQL can be used to PATCH/PUT database entries in a standardized and REST-friendly way.
(1) Accept it is all convention so you can do whatever you want.
(2) Accept it is all convention and follow it
I'd recommend (2) personally as that allows your API consumers to grok your API quicker due to existing expectations. If you go with (1) then do whatever feels right.
The convention:
- POST is always used to create something new. This means the URL should not specify any ID for the object being created, though it can for the hierarchy of objects it belongs to. For example to add an address to an existing user with ID 123 use POST /users/123/addresses with a body of address content.
- PUT is usually used to update an existing something, so for address 3 of that user PUT /users/123/addresses/3 with a body like a POST.
- PATCH is used to partially update an existing something, so PATCH /users/123/addresses/3 with a body just like PUT/POST, and the difference being you supply only the properties on the model you want to change. Often used to patch up large models with small changes.
So the URL is the full address to an individual resource in PUT and PATCH (/users/123/addresses/3), whilst for POST it goes to the resource's parent collection (/users/123/addresses). A POST with an ID as per your example for updating would (by convention) be wrong as it would be expected that POST would create a new instance with its own ID so the one in the URL is not just irrelevant but also misleading. As for your PATCH example for update, it would be expected that the URL tells it which resource to update so (again by convention) the API would not know what to update without that extra bit.
In summary - conventions are to help your API consumers get up to speed via existing expectations whilst also matching the main- and side-effects those consumers expect without them needing to refer to your documentation or treat your API as a special snowflake (as they would see it) amongst the many convention-based ones they probably use from elsewhere.