Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: At this point, are PUT and PATCH helpful?
24 points by seph-reed 45 days ago | hide | past | favorite | 47 comments
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?




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...


The 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/


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


> Most APIs do not store binary blobs. Most APIs operate on complicated sets of database tables

SPARQL can be used to PATCH/PUT database entries in a standardized and REST-friendly way.


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


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


Agree 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)


That seems to muddle interface with implementation. What if your underlying architecture creates new versions of records when they are edited. That wouldn't be idempotent but you wouldn't change your API.


> If you want or need your API to be idempotent, use POST for creation and updating.

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. :)


I 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.


> With PATCH, you don't need to GET anything. You can update fields pretty easily w/o even knowing what's already there:

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.


This comment makes me want to read a book about distributed systems.


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..."


What's TOSS? My searching skills seem to bring up anything but software engineering related topics.


I was teasing. :) There’s no TOSS. You could write a TOSS request, but most software wouldn’t acknowledge it.


You could build an entire http framework around it called "TOSSer"


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.


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


I disagree, i think the original intention of the authors of the http spec is that something like PATCH or PUT edited the files on the server. If you do that against an api, then the behaviour is to edit the source code of the api (WebDav interpretation). That or perhaps the intention is that the meaning is application specific as long as it loosely matches the meaning of the verb and obeys idempotence rules (REST interpretation).

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.


> PATCH or PUT edited the files on the server

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."


Help me out, where in the spec does it obligate the API designer to use verbs other than GET and POST?


It doesn't obligate them to use them. It depends on what the API does and how it's designed.

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").


Agreed about the relevance of the quote you posted. Totally disagree about what it means, in terms of what violates the spec.

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?


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


REST is a buzzword that doesn't actually lead to good api design.


Most 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.


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.


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


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


It is enforced at runtime by frameworks like DRF


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.


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.


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.


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


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.


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.


Yep. 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.


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.


We 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


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


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.


Usage 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.


This 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.


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


I often really like "anti-patterns."

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.


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.





Applications are open for YC Winter 2022

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: