HACKER Q&A
📣 seph-reed

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?


  👤 mleonhard Accepted Answer ✓
Use 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/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...


👤 muzani
I 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


👤 massung
It'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


👤 andrewmcwatters
If 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..."


👤 bawolff
Unpopular 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.

👤 coinspin
If 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.


👤 nreece
Generally, 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


👤 scelerat
I'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.


👤 etaioinshrdlu
Well, 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.


👤 kcartlidge
You 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.


👤 claytongulick
Patch 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/

[2] - https://github.com/claytongulick/json-patch-rules

[3] - https://github.com/claytongulick/mongoose-json-patch

[4] - https://github.com/Starcounter-Jack/JSON-Patch


👤 bedobi
One 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.


👤 throwawayboise
It 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.

👤 eldelshell
I'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.

👤 _v8fn
We at [redacted] 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

👤 ytch
My 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


👤 avoidwork
Hi,

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.


👤 PaulHoule
POST 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.