The way I've been segmented them is based on idempotency.
If you repeat the same call multiple times, do you get the same result as if you just ran it once? Then PUT is appropriate.
But if you have side-effects like creating new resources, that would result in different action each time you make the call, then POST it is.
Idempotent methods include GET, HEAD, PUT and DELETE, the resource should always end up in the same state after calling them N times (barring errors/exceptions and such of course). I'm fairly I got this from when I initially read the specification, it's probably mentioned with a bit more grace in the HTTP/1.1 spec.
- POST creates
- PUT replaces (i.e. edit, but you need to provide the whole resource)
- PATCH edits (i.e. you can only provide some fields)
APIs rarely implement all these properly in practice but that's my understanding of the theory.
I’ve also implemented some GET endpoints that are a GET but have a side effect of marking something as read. (Normally as a variant to an existing endpoint for sessioned user).
I would expect at a minimum though if you are doing writes during a GET it should be idempotent.
That's different, and safer, than something like a "read" bit on an entity, presumably tracked in an application data layer. I don't think you can mark something as "read" in your application from a GET request. Even if your server sees the response to that GET request as successful, it doesn't necessarily mean that the requesting client actually successfully received the response. As one of infinitely many possible counter-examples, consider a middlebox between a client and your server, where one client request to the server may generate N requests from the middlebox to the server.
Let’s say you have some notification resource which is a link redirecting to the thing that triggered the notification. Ideally the notification will automatically be marked read after the user sees the thing they clicked.
My setting the read bit in the GET that makes the redirect you open up. 2 negative possibilities:
- if someone could guess the GUIDs of the notifications they could CSRF a users notifications as marked read. (Unlikely and low impact if it does occur). - Adds the potential that the client may not have loaded page after the redirect and seen the resource.
There is a UX tradeoff now though if we make this a separate PUT after the page loads:
- in a web application context the user will have to either enable JavaScript so the app can automatically mark this as read or have a separate form on every landing page to mark it as read.
Another alternative would be to make this a POST form to view the notification that redirects but you have in effect the same issue of the user maybe not loading the page after the redirect.
At the end of the day for something as minor as a notification being marked read (as a result of a user clicking directly on it), some idempotent modification can work out and be easy to implement.
Now to be clear I am referring to a purpose built endpoint for a web application.
We expose 1000s of truly restful endpoints that are used outside of a web context and something like this doesn’t really make sense for them.
There are just so many ways for GET requests to be delivered to a server (or load balancer, or IP, or domain, or...) multiple times for a given client request. That capability is built in to HTTP and exploited in more places than you can ever hope to account for, or even detect.
> 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.
If you have a longer-running query you could alternatively construct a Query resource of some sort and then GET it until it's ready.
PUT - is effectively an "upsert" at a specific url. Doesn't exist? Create it, does exist? replace it.
PATCH - update a resource with a diff, at a specific url.
POST - this is a RPC, in the case of a REST API it can be used to create a new resource where the "id" is not provided and set by the server, it then redirects to the new url.
POST can be used for any RPC endpoints, even as part of a REST api.
> PUT - Asks the server to edit/update an existing resource
Maybe I've been doing it wrong all these years but it seems to me that the guides flip-flops the responsibility of POST and PUT. My understanding is that POST should edit/modify while PUT creates/replaces a resource.