DELETE on non-existent resource

18,157 views
Skip to first unread message

pn

unread,
May 28, 2013, 2:44:17 PM5/28/13
to api-...@googlegroups.com
Yesterday I had a lengthy discussion with a colleague about what the response code should look like when a client performs a DELETE on a non-existent resource.

In my opinion you can look at it in two ways, either:

a) An HTTP request is an intent, i.e. it doesn't matter what is done as long as the end result is the intended one (i.e on a DELETE I want the specified resource to "not exist" from then on).
b) An HTTP request is an action that must be performed. Which means that if the action itself cannot be performed an error should be returned.

Say you have the following request: DELETE /users/123

Say the user "123" doesn't exist. If the more correct interpretation is a) then the end game is for the user to "not exist" so mission acomplished I guess (even if nothing was done to acheive it), i.e. a 204 would be appropriate to indicate sucess. However if the "right" way to look at it is b) then the more appropriate response would be 404 or 410, since the delete action itself wasn't carried out in the request (also the fact is that the URI /users/123 doesn't exist would imply a 404 or 410)

Although at first glance the 2nd option seems more correct to me, in the HTTP spec it says (on DELETE)


The client cannot be guaranteed that the operation has been carried out, even if the status code returned from the origin server indicates that the action has been completed successfully.

Which it seems to me to imply that delete request isn't solely the action itself that matters, since the server may not perform it at all (at that moment), it seems to imply that what matters most is the intent, ergo option b).... on the other hand some REST "VIPs" :-) (see this thread) seem to think that the most appropriate response would be either a 404 or 410 -  i.e. interpretation a)


Which interpretation do you think is more "formally" correct (if there is a such a thing)?



Cheers,
Pedro

P Burrows

unread,
May 28, 2013, 2:53:45 PM5/28/13
to api-...@googlegroups.com
I have to think it depends on your application. If it is such that it is reaonable to expect that a client would not attempt to delete a record which does not exist, then you should give feedback that the record did not exist -- likely there is an error in their logic that they need to fix. If for your application it is likely that users will request to delete records which may or may not exist, then silently doing nothing might be appropriate.

As a compromise, you could just return the number of records which were deleted from the operation. In that case, a 0 would give the information that the record was not found.


--
with excessive obsequiousness,

Patrick Burrows
http://www.BurrowsCorp.com



--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Repenning, Jack

unread,
May 28, 2013, 4:00:48 PM5/28/13
to api-...@googlegroups.com
On May 28, 2013, at 11:44 AM, pn <pnuno....@gmail.com> wrote:

Although at first glance the 2nd option seems more correct to me, in the HTTP spec it says (on DELETE)
The client cannot be guaranteed that the operation has been carried out, even if the status code returned from the origin server indicates that the action has been completed successfully.
I don't think this language speaks to your case (DELETE something that doesn't exist in the first place). I think the point of that language is that a DELETE might actually enqueue an internal request, and return status before the request is complete, or anyway before the results are visible to the client. Perhaps "DELETE id-of-something" does the delete and triggers a reindexing, but an immediately subsequent "GET that-same-id" might still see the object -- if it manages to sneak in before the reindexing transaction is complete. If the underlying database is reasonably robust (crash-recovery and roll-forward and all that), then it's fair to claim the DELETE has reliably happened even though it hasn't actually happened quite yet.

It seems most RESTful to me to say that "DELETE /users/123" addresses the resource (object) /users/123, and says to it "DELETE thyself." If there is no /users/123, then that's a 404. As an analogy, the Unix "rm" command reports an error if you ask it to delete something that does not exist (though, indeed, there is also a command-line switch to stifle the whine). 

Returning a (possibly empty) list of deleted id(s) seems wrong here: you only asked for one thing to happen, whence then this "list"? In contrast, "DELETE /users?first_name=Fred" has every right to return a list of results, possibly including not only "those deleted" but also "those that exist, and match your query, but couldn't be deleted for some other reason, and by the way here's an explanation" (if that's meaningful for you). In the degenerate case "DELETE /users?id=123", us humans of course can see that there can be at most one result, but that's too subtle to expect of a protocol: returning a list is still justified, returning status 404 is not (unless there is no resource "users"!), and you still get to decide how whiny to be if there was nothing to delete.



-- 
Jack Repenning

sune jakobsson

unread,
May 28, 2013, 5:05:45 PM5/28/13
to api-...@googlegroups.com
If the parameters are bogus, return 404, regardless of the operation.
The DELETE does not imply that the resource MUST disappear immediately, it could possibly be tagged to batch or self destruction.

Sune


pn

unread,
May 29, 2013, 7:23:41 AM5/29/13
to api-...@googlegroups.com
Right, I guess the first validation to do then is to check the URI validity and return a 404 if that URI doesn't exist.

Thanks for all the input.

CJunge

unread,
May 30, 2013, 12:13:40 AM5/30/13
to api-...@googlegroups.com
DELETE is said to be idempotent, so calling DELETE /users/123 as many times as you want should have the same effects.

see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Calling DELETE /users/123 and getting a 204 back, then calling it again & getting a 404 back seems to NOT be idempotent to me. Calling a GET /user/123 after the first or second DELETE would return the 404.

I could be wrong though, glad to be corrected!

Cameron

sune jakobsson

unread,
May 30, 2013, 2:31:09 AM5/30/13
to api-...@googlegroups.com
Idempotent operation only looks at the input, and if it has a previous answer, return it.

Sune


--

Abhijit Tambe

unread,
May 30, 2013, 7:01:04 AM5/30/13
to api-...@googlegroups.com
Idempotency is defined in terms of 'unintended side effects at the server', not 'results seen by the client'. The point of idempotent operations is to ensure that there are no unintended actions performed by the server.

Calling GET /abc multiple times can result in different results or status codes being returned to the client (resource state might have changed or resource might no longer exist), but GET is perfectly idempotent (for a correctly implemented server).

Similarly, calling DELETE /abc multiple times is idempotent, even if it results in different status codes being returned to the client. The whole idea is that nothing has changed *unintentionally* at the server no matter how many times that DELETE operation is performed.



--

Austin Wright

unread,
Jun 17, 2013, 3:53:36 AM6/17/13
to api-...@googlegroups.com
Idempotent would mean that the server state is the same following any nonzero number of consecutive requests. It doesn't imply that you'll get the same response back. (I can't actually think of a non-safe idempotent method where you'll get the same response, or at least when using conditional request headers.)

If the item is was successfully deleted, return 200 (the resource exists as of the time of the request, and the action was executed). If it's being queued for execution, return 202. If the resource has already been deleted, return 410. If it otherwise doesn't exist, return 404.

Mike Kelly

unread,
Jun 17, 2013, 5:37:26 AM6/17/13
to api-...@googlegroups.com

It doesn't even really mean that the server state is the same (e.g. page views via GET incrementing a visit count).

Idempotent just means that the client intent is the same regardless of how many times the request is issued.

Cheers,
M

--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.

pn

unread,
Jun 18, 2013, 4:04:53 AM6/18/13
to api-...@googlegroups.com
The way I explain idempotency to myself is that if you consider an API the interface to a "business" system, idempotency means the "business" system state remains the same however many idempotent request one makes. Now that doesn't mean counters get updated, logs created, etc. The server state can change, however the "business" state remains the same.

I guess you could say that idempotent methods are deterministic in that the "business" result (emphasis on business, I'm not talking about protocol exchages or parallel systems like logging and such) is always the same.

Hans Ridder

unread,
Jul 7, 2013, 1:33:27 PM7/7/13
to api-...@googlegroups.com
I think most of the responses so far are missing the point of *why* methods are idempotent. One reason for idempotent methods is to allow a client to simply retry a request where the outcome is unknown, such as a network error. If a client does, for example, a PUT or DELETE, and gets a "timeout", "connection reset", or even 500 status, it can safely just do the same request again without consequences, until it either gets a better response or gives up.

The correct way to think about the problem is *not* what the server thinks or knows the state of the system is, but what clients think it is (or *was at some point*).

With this in mind, I think the pedantic answer to the question is that DELETE to a non-existent resource *should be* that it returns 200. Having every client in the world handle 404 as "success" when many (all?) other 4xx errors indicate a real problem with the request just makes client's lives more complicated. Why should the should the client get a different result depending on whether the request was retried, or better yet, some other client or process has deleted the resource since the client saw that it existed? Servers already need to handle methods on non-existing resources (consider PUT creating a new resource). It's not a significant burden for servers and is easier to build distributed systems around.

The pragmatic answer to the question is that even if you believe the above, real servers will get it wrong and you have to write that damn "404 is success" code anyway, or your client will fail when it retries, or some other client has deleted a resource right after you checked and saw it was there. I'll bet there's *lots* of client code that gets this wrong and fails miserably when the server state is not what it expected. :-)

-hans

pn

unread,
Jul 8, 2013, 5:03:46 AM7/8/13
to api-...@googlegroups.com
Having a different responses to the same request doesn’t mean the client can’t try to repeat a request when it doesn’t know what the outcome was for a previous one… all it means is (as you said) that the client has to be ready to handle whatever response may be returned. The idempontency is about reaching the same outcome (in terms of state) however many request are made (at least the way I see it).

Initially my opinion was the same as yours Hans, however I guess that there may be value (for the client) to distinguish between a deletion on an existing resource and a deletion on an non-existing resource. And if one doesn’t return a 404 then it’s impossible for the client to do that (since as you said doing a GET first doesn’t ensure that when the actual DELETE is done the resource is still there).

Practically speaking, for the servers I see two options, either they try to accommodate “incomplete clients” (those that don’t handle every response, or even the most basic ones, like 404) and always return 204 or 200, or they can follow a more, let’s say “strict” approach (some might say the "correct" approach), and return a 404 on any method performed on an non-existing URI.


Cheers,
Pedro
Message has been deleted

Austin Wright

unread,
Jul 11, 2013, 4:17:16 AM7/11/13
to api-...@googlegroups.com
I'm inclined to disagree with this because it's not true that the resource is always deleted.

If the client sends an If-Match header, but the condition fails, that's clearly an error, not 200 OK. So what happens if the condition fails because the resource doesn't exist at all? 200 OK? Precondition failed? If that sounds reasonable, then what about "If-Match: *"? Generally, 404 takes precedence over 412.

What if there's an authorization problem? Perhaps some resources can only be deleted by administrators, others can be deleted by anyone. Are you really saying 200 in a DELETE means "yep, no such resource exists anymore, if it ever did"?

Since as you point out the state of the server will be the same, perhaps the status code can be the same. Ok, it can be, but should it be? We have 404 and 410 as separate status codes, even though they both represent the same server state.

What about 301 Moved permanently and 410 Gone? Do you really want to lump 200, 301, 404, and 410 together into a single status code, 200, just because some clients might not care about the distinction?
Reply all
Reply to author
Forward
Message has been deleted
0 new messages