6 ms·
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?
- nreece 5y agoGenerally, POST is to create a new entity, while PUT is to fully update an existing entity. PATCH is used for partial updates, if necessary in a use case. I was recently working with the Vultr API, and they follow this pattern as well: https://www.vultr.com/api/#section/Introduction https://www.vultr.com/api/#section/Introduction
- seph-reed 5y agoI've read this in most of the StackO threads I found on it. And I love the idea of it. But it kind of feels like the fact that so many people have to explain it and nothing really enforces it except code reviews is... I dunno. It's like when someone has big ideas about how things are gonna go, but then reality ends up taking some other opportunity path.
- deleted 5y ago[deleted]
- weird-eye-issue 5y agoIt is enforced at runtime by frameworks like DRF
- claytongulick 5y agoPatch is extraordinarily helpful when coupled with json-patch[1]. 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/ http://jsonpatch.com/ [2] - https://github.com/claytongulick/json-patch-rules https://github.com/claytongulick/json-patch-rules [3] - https://github.com/claytongulick/mongoose-json-patch https://github.com/claytongulick/mongoose-json-patch [4] - https://github.com/Starcounter-Jack/JSON-Patch https://github.com/Starcounter-Jack/JSON-Patch
- avoidwork 5y agoHi, 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.
- seph-reed 5y agoI often really like "anti-patterns." They're usually a case of a ["desire path"](https://miro.medium.com/max/2592/0%2AD1R7QvewXmwUVytD https://miro.medium.com/max/2592/0%2AD1R7QvewXmwUVytD.) Typically, it says more to me about the designer than the users.
- wvenable 5y agoIt doesn't really matter though. 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.
- happytoexplain 5y agoUsage of POST to update is so common, I don't think it's unreasonable to say it's a de-facto standard. Sort of like how if an English word/phrase is misused enough, the "wrong" version eventually makes it into dictionaries.
- gls2ro 5y agoThis is the first time I hear that usage of POST to update is common. 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.
- massung 5y agoIt's important to remember that aside from "convention" (and likely having a few helper functions defined in whatever server library you're using), there's nothing special about the method/verb in the HTTP protocol. You could literally define FOO and BAR methods in your API and use those if you found them useful. 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
- seph-reed 5y agoI guess I'd expect 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.
- wglass 5y agoAgree with your sentiment, but I've always seen PUT as idempotent, not POST. 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)
- PaulHoule 5y agoPOST is all you need (if you think it is all RPC and goddamn the http verbs) but PUT is common and correct in many cases.
- seph-reed 5y agoBy RPC do you mean https://en.wikipedia.org/wiki/Remote_procedure_call https://en.wikipedia.org/wiki/Remote_procedure_call ?
- coinspin 5y agoIf you're building a REST API you might as well follow the semantics of GET/PUT/POST/PATCH/DELETE. Overloading post requests may seem convenient and tidy but there is a spec for a reason. If you prefer more of a one query or request to rule them all then GraphQL may align better to your preferences.
- throwawayboise 5y agoIt may be surprising, but I've run into HTTP clients that could only do GET and POST. So if I had needed to use an API with PATCH I would have been SOL in that situation.
- toast0 5y agoYep. If you want to be able to use your api almost everywhere, just use POST. 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.
- bawolff 5y agoUnpopular opinion, but i've always hated this trend of using weird http verbs for rest apis. Half the time it doesn't really fit right, and is a weird layering violation. I think they make sense for WebDav but not general apis.
- TylerE 5y agoREST is a buzzword that doesn't actually lead to good api design.
- bawolff 5y agoMost buzzwords don't. You can make good rest apis, you can make bad rest apis. You can make good non-rest apis and bad nom-rest apis. There will never be a buzzword that replaces the neccesisty of good program design.
- smt88 5y agoIt's not a "trend", it's literally part of the HTTP (and therefore REST) specification[1]. It's theoretically the correct way to do things. 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 https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
- jholman 5y agoHelp me out, where in the spec does it obligate the API designer to use verbs other than GET and POST?
- thunderbong 5y agoIt doesn't. But a lot of the Javascript frameworks follow this and it's considered a de facto standard. Also, most modern SAAS services have APIs that follow this de facto standard.
- 5y ago
- etaioinshrdlu 5y agoWell, the truly devious thing is to do what Rails does and have a second, fake, method field in the request body to designate the "intended" HTTP method not supported by the browser/intermediaries. I agree with other commenters that the whole thing is rather silly.
- bedobi 5y agoOne of the APIs I maintain is for user profiles. A user profile has all kinds of stuff, eg name, email, phone, timezone etc etc. 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.
- andrewmcwatters 5y agoIf you don't really care that much, you could try TOSS. Which would be useful to tell the server, "Hey, you deal with this, it's not my problem anymore." 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..."
- kivihiinlane 5y agoWhat's TOSS? My searching skills seem to bring up anything but software engineering related topics.
- andrewmcwatters 5y agoI was teasing. :) There’s no TOSS. You could write a TOSS request, but most software wouldn’t acknowledge it.
- seph-reed 5y agoYou could build an entire http framework around it called "TOSSer"
- ytch 5y agoMy company uses a lot PHP, the problem that prevent me uploading file via PUT is PHP didn't parse `multipart` to `$_FILES` in PUT request: https://bugs.php.net/bug.php?id=55815 https://bugs.php.net/bug.php?id=55815
- muzani 5y agoI think it's just clearer. There's nothing preventing you from just using GET and POST, but the others are already fully supported by everything. 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
- scelerat 5y agoI'd stick to the spec and the conventions around them, if for the only reason that many tools have default assumptions based around these specs and once you start to veer away, you're coding around your tools instead of with them. i.e. use POST to create new things and PUT and/or PATCH to change existing things.
- eldelshell 5y agoI'm just going to add that it also helps to describe your intent on code. For example, on Quarkus or other Java frameworks you use javax.ws.rs annotations. So if you're reading your code and see @GET or @PATCH you know what that method is doing even without reading the method signature. If you then add swagger it will generate a nice UI with colors and all that also helps to describe the purpose.
- mleonhard 5y agoUse PUT [0], GET, and DELETE to upload/download/delete binary blobs at the same URL. A successful PUT response is "201 Created" [1] with a "Location" header with the final URL of the blob. PUT is also idempotent. 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/PUT https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PU... [1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201 [2] https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PA...
- ojhughes 5y agoThe Kubernetes API implements patch correctly FWIW. Patching objects in k8s is advisable where possible instead of replacing as it allows the control plane to gracefully update the resources (without downtime). https://blog.atomist.com/kubernetes-apply-replace-patch/ https://blog.atomist.com/kubernetes-apply-replace-patch/
- mleonhard 5y agoI found nothing in the docs [0, 1] about downtime due to Replace or Patch. Both commands change the spec. Downtime from a spec change seems to be unrelated to the manner of changing the spec. 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-api/v1.21/#resource-operations-update https://kubernetes.io/docs/reference/generated/kubernetes-ap... [1] https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ https://kubernetes.io/docs/tasks/manage-kubernetes-objects/u... [2] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If... [3] https://docs.bazel.build/versions/main/command-line-reference.html https://docs.bazel.build/versions/main/command-line-referenc... [4] https://github.com/flutter/flutter/issues/80849 https://github.com/flutter/flutter/issues/80849
- singhravi1 5y agoWe at Startxlabs use the following logic with the request methods, - GET: to get particular object or list of objects - POST: to create a new object - PATCH: to update a particular object - PUT: to update multiple objects in a single request - DELETE: to delete the object/s
- kcartlidge 5y agoYou have two main approaches. (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.