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.
Related
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.
I have a REST API and I want to handle all HTTP requests via POST request.
Is there any performance or other kind of issue in using just POST to perform all CRUD operations requested by a user, which sends a JSON containing some data and the operation to be performed?
Technically, the HTML used in the Web only supports GET and POST and this is more or less the reference implementation of a REST architecture.
So, while this is possible I wouldn't advocate for something like that as the idempotency property of PUT and DELETE provide some other benefits in case of network issues where a client can automatically resend the request regardless whether the initial request, whose response might have just got lost mid-way, actually performed its task or not. The result should always be an updated/created resource or a removed URI mapping to the actual resource (or even a removal of the actual resource) as DELETE technically just removes the URI mapping.
In regards to put some operations in the payload, it depends. This actually sounds very RPCy to me, similar to SOAP i.e. If the operation however is defined by a well-defined media-type, like in the JSON Patch case, I guess this is not wrong. Similar to the Web, however, a server should use some resource that is able to teach a client on how to build up a request, like HTML does with forms. This will not only teach the client on what fields the server supports for the target resource but also where to send the request to as well as the media-type and HTTP operation to use, which might be fixed to POST as in the HTML case.
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.
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.
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.