When designing Restful API, should I use DELETE or POST for UNFOLLOW? - rest

I have this question in my mind for a day, I tried to do some reading from RESTful Web Services Cookbook and other stackoverflow posts, but still did not get a convincing answer to this question:
Assuming I have a database table storing relationships between two users, the relation represents that if user A is following user B (e.g. on Instagram/Twitter).
userId|userId
------|------
userA | userB
userA | userC
....
So now if user A would like to unfollow user B, then should this API be DELETE or POST?
In RESTful Web Services Cookbook page 11, it says:
"The DELETE method is idempotent. This implies that the server must return response code 200 (OK) even if the server deleted the resource in a previous request. But in practice, implementing DELETE as an idempotent operation requires the server to keep track of all deleted resources. Otherwise, it can return a 404 (Not Found)."
Does this suggest us to not use DELETE whenever we can avoid?
Thanks for any insight on this question!

DELETE is for deleting specific resources. So if DELETE is appropriate for you depends on if you have a single resource that 'represents' the follow relationship between two users.
For example, if you have a resource as such:
/api/userA/follows/userB
Then it could be said that this resource represents the relationship between the two. It has a unique url, so this url can be deleted at which point I would expect the relationship to be severed.

Building on top of Evert's answer, the DELETE method is suitable for your needs, as long as you have a resource that represents the relationship between two users.
The semantic of the DELETE method is defined in the RFC 7231:
4.3.5. DELETE
The DELETE method requests that the origin server remove the association between the target resource and its current functionality. [...]
The DELETE method is, in fact, meant to be idempotent, but your quote is fundamentally wrong when it relates idempotency with the status code.
As I previously mentioned in this answer, idempotency is not related to the status code itself. Idempotency is about the effect produced on the state of the resource on the server, even if the response for the subsequent requests are different from the first request.
Consider a client performs a DELETE request to delete a resource from the server. The server processes the request, the resource gets deleted and the server returns 204. Then the client repeats the same DELETE request and, as the resource has already been deleted, the server returns 404 and that's totally fine.
Despite the different status code received by the client, the effect produced by a single DELETE request is the same effect of multiple DELETE requests to the same URI.

Related

Restful way to delete a write-protected resource

In my API, resources can be write-protected. Trying to DELETE such a resource will return a 409 (Conflict) response.
For users that are allowed to change the protected state of a resource, I want to introduce the option to delete protected resources with one request. How should this option be passed?
Possible solutions:
Request body -- should not be used with delete requests
Query parameter -- changes the URI, so technically refers to a different resource
Custom header -- generally discouraged
Standard header -- none apply
Two requests -- not atomic, things could happen in-between (eg another user modifying the resource)
Alternative endpoint -- not restful?
Related Questions
In REST API, can DELETE methods have parameters?
Answer says yes to query parameters, but asks about deleting a subset of a collection
REST, HTTP DELETE and parameters
Asks about a confirmation flag, answers say it should be handled in UI instead of API
Also says it violates the uniform interface principle, but doesn't explain why and how
Also argues that using query parameters would violate URI principle
RESTful Alternatives to DELETE Request Body
Accepted answer says to use the body, but many commenters report technical issues
Query parameters are suggested as alternative, concern about URI principle is raised
Is an entity body allowed for an HTTP DELETE request?
Says not to use the request body, even if technically allowed
Whats the best way to design DELETE for a restful resource
Says to use query parameters, but again in a subset context
For users that are allowed to change the protected state of a resource, I want to introduce the option to delete protected resources with one request. How should this option be passed?
If the meaning of the request message is consistent with HTTP DELETE, then you should probably just use HTTP DELETE, rather than trying to invent a dialect that allows you to discriminate between DELETE and no-no-I-really-mean-it-DELETE.
Are your message semantics consistent with HTTP DELETE? You may want to consider this observation in RFC 9110
Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.
DELETE is the method token we send to a web server when we want that server to stop sharing representations of a resource. It's semantics are rooted in the transfer of documents over a network domain.
On the other hand, if the message isn't consistent with HTTP DELETE, then you should consider using HTTP POST.
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Fielding, 2009
Here's a way of thinking about the distinction: our goal in creating a "REST API" is to create a facade that disguises our domain service as an HTTP-aware document store.
If what the client is really doing is marking a document as hidden in the store; and as a side effect of that we may make a bunch of changes in our domain service, then DELETE is appropriate.
On the other hand, if what the client is really doing is sending information to our domain service, and as a side effect some documents are going to be hidden, then POST is appropriate.

REST endpoint for complex actions

I have a REST API which serves data from the database to the frontend React app and to Android app.
The API have multiple common endpoints for each model:
- GET /model/<id> to retrieve a single object
- POST /model to create
- PATCH /model/<id> to update a single model
- GET /model to list objects
- DELETE /model/<id> to delete an object
Currently I'm developing an Android app and I find such scheme to make me do many extra requests to the API. For example, each Order object has a user_creator entry. So, if I want to delete all the orders created by specified user I need to
1) List all users GET /user
2) Select the one I need
3) List all orders he created GET /order?user=user_id
4) Select the order I want to delete
5) Delete the order DELETE /order/<id>
I'm wondering whether this will be okay to add several endpoints like GET /order/delete?user=user_id. By doing this I can get rid of action 4 and 5. And all the filtering will be done at the backend. However it seems to me as a bad architecture solution because all the APIs I've used before don't have such methods and all the filtering, sorting and other "beautifying" stuff is usually at the API user side, not the backend.
In your answer please offer a solution that is the best in your opinion for this problem and explain your point of view at least in brief, so I can learn from it
Taking your problem is in isolation:
You have an Order collection and a User collection
User 1..* Orders
You want to delete all orders for a given user ID
I would use the following URI:
// delete all orders for a given user
POST /users/:id/orders/delete
Naturally, this shows the relationship between Users & Orders and is self-explanatory that you are only dealing with orders associated with a particular user. Also, given the operation will result in side-effects on the server then you should POST rather than GET (reading a resource should never change the server). The same logic could be used to create an endpoint for pulling only user orders e.g.
// get all orders for a given user
GET /users/:id/orders
The application domain of HTTP is the transfer of documents over a network. Your "REST API" is a facade that acts like a document store, and performs useful work as a side effect of transferring documents. See Jim Webber (2011).
So the basic idioms are that we post a document, or we send a bunch of edits to an existing document, and the server interprets those changes and does something useful.
So a simple protocol, based on the existing remote authoring semantics, might look like
GET /orders?user=user_id
Make local edits to the representation of that list provided by the server
PUT /orders?user=user_id
The semantics of how to do that are something that needs to be understood by both ends of the exchange. Maybe you remove unwanted items from the list? Maybe there is a status entry for each record in the list, and you change the status from active to expired.
On the web, instead of remote authoring semantics we tend to instead use form submissions. You get a blank form from somewhere, you fill it out yourself, you post it to the indicated inbox, and the person responsible for processing that inbox does the work.
So we load a blank form into our browser, and we make our changes to it, and then we post it to the resource listed in the form.
GET /the-blank-form?user=user_id
Make changes in the form...
POST ????
What should the target-uri be? The web browser doesn't care; it is just going to submit the form to whatever target is specified by the representation it received. One answer might be to send it right back where we got it:
POST /the-blank-form?user=user_id
And that works fine (as long as you manage the metadata correctly). Another possibility is to instead send the changes to the resource you expect to reflect those changes:
POST /orders?user=user_id
and it turns out that works fine too. HTTP has interesting cache invalidation semantics built into the specification, so we can make sure the client's stale copy or the orders collection resource is invalidated by using that same resource as the target of the POST call.
Currently my API satisfies the table from the bottom of the REST, so, any extra endpoint will break it. Will it be fatal or not, that's the question.
No, it will be fine -- just add/extend a POST handler on the appropriate resource to handle the new semantics.
Longer answer: the table in wikipedia is a good representation of common practices; but common practices aren't quite on the mark. Part of the problem is that REST includes a uniform interface. Among other things, that means that all resources understand the same message semantics. The notion of "collection resources" vs "member resources" doesn't exist in REST -- the semantics are the same for both.
Another way of saying this is that a general-purpose component never knows if the resource it is talking to is a collection or a member. All unsafe methods (POST/PUT/PATCH/DELETE/etc) imply invalidation of the representations of the target-uri.
Now POST, as it happens, means "do something that hasn't been standardized" -- see Fielding 2009. It's the method that has the fewest semantic constraints.
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. -- RFC 7231
It's perfectly fine for a POST handler to branch based on the contents of the request payload; if you see X, create something, if you see Y delete something else. It's analogous to having two different web forms, with different semantics, that submit to the same target resource.

Can I use DELETE to update a flag indicating that this element is deleted?

I'm building an API and I want to follow best practice so I used PUT to insert, POST to update and GET to fetch, and I want to use DELETE when the client requests to delete an item but the thing is in the database we won't be actually deleting anything, we're simply updating a flag indicating that this item is deleted, so does that still fall under DELETE or should that request be POST instead?
What you talking about is called "soft delete" - when a record is marked deleted, it is not available through GET, but data remains in the database. For all client purposes that is still a delete operation, implementation is your own and should not concern your clients.
So yes, it is perfectly fine to use HTTP verb DELETE to do a soft delete.
From the client perspective, the data is not there anymore (it cannot see that piece of data if the client calls the GET endpoint), so you can use the DELETE verb for this endpoint.
One important thing to keep in mind is to stay GDPR compliant if the end-user is from an EU country (General Data Protection Regulation forces you to delete the user private data upon their request. Making the data unavailable to the user, but keeping it on your server (by flagging it as deleted) is a direct violation of the user rights).
As answered by others, you can use the HTTP DELETE method for this case.
Also, a small correction in the other standards you have mentioned. It has to be HTTP POST to create and PUT to update your resources.

REST DELETE idempotency

Given a DELETE request that will delete resource at an integer index, does the possibility of recreation of a resource at that index break strict idempotency?
e.g. a DELETE request is made to /api/resource/123 deletes the resource at 123. Then a post request is made which creates a new resource which can be retrieved by a GET request to the same url.
It seems to me that for the original DELETE to be properly idempotent, the API should never create a new, different, resource with a previously used id, but I can't find a clear reference.
Given a DELETE request that will delete resource at an integer index, does the possibility of recreation of a resource at that index break strict idempotency?
No.
RFC 7231
A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.
Idempotent methods are distinguished because the request can be repeated automatically if a communication failure occurs before the client is able to read the server's response. For example, if a client sends a PUT request and the underlying connection is closed before any response is received, then the client can establish a new connection and retry the idempotent request. It knows that repeating the request will have the same intended effect, even if the original request succeeded, though the response might differ.
Notice: a generic client can retry the request; the client doesn't need to know anything about your particular implementation.
It seems to me that for the original DELETE to be properly idempotent, the API should never create a new, different, resource with a previously used id, but I can't find a clear reference.
That's not at all the case. Think about a static website. Can you, the website owner, delete foobar.html ? Of course you can. Can you recreate it later? Of course. If that's true, then it ought to be true for remoted editing as well.
And if it is true for remote editing of a web site, it should also be true for any other REST API. The point of the uniform interface is that consumers don't need to know if they are talking to a file system, a document store, a database, or some sophisticated service. The job of the API is to act as an integration layer, so that the underlying implementation acts just like the web.
In fact, this has nothing to do with the idempotent behavior of the methods.
This is the problem of naming resources. Because If the resource never existed, the deletion will behave exactly as after the resource has been deleted.
Yes, a second request will delete the new resource with the same name.
But if you are experiencing this problem, simply create a unique resource name.(UUID for example)
You can also try using the database index. Even if the entry with the key "123" is deleted - the database does not create it again.

REST: Prevent creation of duplicate resources via conditional POST?

I've been searching for best practices for preventing the accidental creation of duplicate resources when using POST to create a new resource, for the case where the resource is to be named by the server and hence PUT can't be used. The API I'm building will be used by mobile clients, and the situation I'm concerned about is when the client gets disconnected after submitting the POST request but before getting the response. I found this question, but there was no mention of using a conditional POST, hence my question.
Is doing a conditional POST to the parent resource, analogous to using a conditional PUT to modify a resource, a reasonable solution to this problem? If not, why not?
The client/server interaction would be just like with a conditional PUT:
Client GETs the parent resource, including the ETag reflecting its current state (which would include its subordinate resources),
Client does a conditional POST to the parent resource (includes the parent's ETag value in an If-Match header) to create a new resource,
Client gets disconnected before getting the server response, so doesn't know if it succeeded,
Later, when reconnected, the client resubmits the same conditional POST request,
Either the earlier request didn't reach the server, so the server creates the resource and replies with a 201, or the earlier request did reach the server, so the server replies with a 412 and the duplicate resource isn't created.
Your solution is clever, but less than ideal. Your client may never get his 201 confirmation, and will have to interpret the 412 error as success.
REST afficianados often suggest you create the resource with an empty POST, then, once the client has the id of the newly created resource, he can do an "idempotent" update to fill it. This is nice, but you will likely need to make DB columns nullable that wouldn't otherwise be, and your updates are only idempotent if no-one else is trying to update at the same time.
According to ME, HTTP is flaky. Requests timeout, browser windows get closed, connections get reset, trains go into tunnels with mobile users aboard. There's a simple, robust pattern for dealing with this. Unsafe actions should always be uniquely identified, and servers should store, and be able to repeat if necessary, the response to any unsafe request. This is not HTTP caching, where a request may be served from cache but the cache may be flushed for whatever reason. This is a guarantee by the server application that if an "action" request is seen a second time, the stored response will be repeated without anything else happening. If the action identity is to be generated by the server, then a request-response should be dedicated just to sending the id. If you implement this for one unsafe request, you might as well do it for all of them, and in so doing you will escape numerous thorny problems: successive update requests wiping out other users' changes, or hitting incompatible states ("order already submitted"), successive delete requests generating 404 errors.
I have a little google doc exploring the pattern more fully if you're interested.
I think this scheme would work. If you want to ensure POST does not result in duplicates, you need the client to send something unique in the POST. The server can then verify uniqueness.
You might as well have the client generate a GUID for each request, rather than obtaining this from the server via a GET.
Your steps then become:-
Client generates a GUID
Client does a POST to the resource, which includes the GUID
Client gets disconnected and doesn't know if it succeeded
Client connects again and does another POST with the same GUID
Server checks the GUID, and either creates the resource (if it never received the first POST) or indicates that this was a duplicate
It might be more restful to use PUT, and have the client decide the resource name. If you did not like the choosen name, you could indicate that you had created the resource but that it's canonical location was somewhere of the server's choosing.
Why not simply do duplicate detection on the server based on the actual resource, using whatever internal mechanism the server chooses to use.
It's just safer that way.
Then you return the URL to the appropriate resource (whether it was freshly created or not).
If the parents ETag is based on the state of sub resources, then it's not a reliable mechanism to check for "duplicate resources". All you know is that the parent has "changed", somehow, since last time. How do you even know it's because your old POST was processed after disconnect? Could be anything changed that ETag.
This is basically a optimistic locking scenario being played out, and it comes down to another question. If the resource is already created, what then? Is that an error? Or a feature? Do you care? Is it bad to send a creation request that's silently ignored by the server when the resource already exists?
And if it already exists, but is "different" enough (i.e. say the name matches but the address is different), is that a duplicate? is that an update? is that a error for trying to change an existing resource?
Another solution is to make two trips. One to stage the request, another to commit it. You can query the status of the request when you come back if it's interrupted. If the commit didn't got through, you can commit it again. If it did, you're happy and can move on.
Just depends on how unstable your comms are and how important this particular operation is whether you want to jump through the hoops to do it safely.