250

Given that the DELETE verb in HTTP is idempotent, when I issue the following request, what should happen the second (or third, or fourth, etc...) time I make it?

DELETE /person/123

The first time, the resource is deleted and I return a 204 (successful, no content). Should I return a 204 on subsequent calls or a 404 (not found)?

1
  • 5
    A more generic Q&A about whether idempotency includes status codes: stackoverflow.com/q/24713945/2157640 Spoiler, it does not. Commented Sep 17, 2021 at 14:07

7 Answers 7

278

As HTTP requests in a stateless system should be independent, the results of one request should not be dependent on a previous request. Consider what should happen if two users did a DELETE on the same resource simultaneously. It makes sense for the second request to get a 404. The same should be true if one user makes two requests.

I am guessing that having DELETE return two different responses does not feel idempotent to you. I find it useful to think of idempotent requests as leaving the system in the same state, not necessarily having the same response. So regardless of whether you DELETE an existing resource, or attempt to DELETE a resource that does not exist, the server resource state is the same.

Sign up to request clarification or add additional context in comments.

17 Comments

Thank you. That makes so much sense. I was indeed thinking of idempotent as returning the same response.
If you DELETE something that doesn't exist, you should just return a 204 (even if the resource never existed). The client wanted the resource gone and it is gone. Returning a 404 is exposing internal processing that is unimportant to the client and will result in an unnecessary error condition.
@DarrelMiller I guess the key concept here is that you should not use DELETE to check if a resource exists, you'd first use GET for that. Then, if the response is 200, you'd perform a DELETE; otherwise don't even bother to do that. So I think it makes sense to always return a 204 on DELETE.
@Brian The RFC says it's supposed to behave like rm. rm returns an error if it doesn't exist. tools.ietf.org/html/rfc7231#section-4.3.5
@DaxFohl Technically, it says, "this method is similar to the rm command," which I interpret as an analogy, rather than a recommendation on behavior.
|
223

I agree with what the current chosen answer has said, that the 2nd (and 3rd, 4th, ...) DELETE should get a 404. And, I noticed that answer has 143 up votes but also has an opposite comment which has 54 up votes, so the community is divided into 2 camps in roughly 3:1 ratio. Here comes more information to settle this long time debate.

  1. First of all, let's NOT start with what "I" think, what "you" think, or what yet another book author thinks. Let's start with the HTTP specs i.e. RFC 7231.
  • RFC 7231, section 4.3.5 DELETE happened to only mention a successful response should be 2xx, but it did not call out what a subsequent DELETE would get. So let's dig deeper.

  • RFC 7231, section 6.5.4 404 Not Found says 404 response is for a resource does not exist. Since no specific http method (in particular, not DELETE) being called out to be treated otherwise, we can intuitively get an impression (and rightfully so), that my request DELETE /some/resource/which/does/not/exist should result in a 404. Then, DELETE /some/resource/which/happened/to/be/removed/by/someone/else/five/days/ago might as well also return a 404. Then, why should DELETE /some/resource/i/deleted/five/seconds/ago be any different? "But how about idempotency?!", I can hear you are screaming that. Hang on, we are about to get into that.

  • Historically, RFC 2616, published at 1999, was the most-referenced HTTP 1.1 specs. Unfortunately its description on idempotency was vague, that leaves room for all these debates. But that specs has been superseded by RFC 7231. Quoted from RFC 7231, section 4.2.2 Idempotent Methods, emphasis mine:

    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. Of the request methods defined by this specification, PUT, DELETE, and safe request methods are idempotent.

    So, it is written in the specs, idempotency is all about the effect on the server. The first DELETE returning a 204 and then subsequent DELETE returning 404, such different status code does NOT make the DELETE non-idempotent. Using this argument to justify a subsequent 204 return, is simply irrelevant.

  1. OK so it is not about idempotency. But then a follow-up question may be, what if we still choose to use 204 in subsequent DELETE? Is it OK?

    Good question. The motivation is understandable: to allow the client to still reach its intended outcome, without worrying about error handling. I would say, returning 204 in subsequent DELETE, is a largely harmless server-side "white lie", which the client-side won't immediately tell a difference. That's why there are ~25% people doing that in the wild and it seemingly still works. Just keep in mind that, such lie can be considered semantically weird, because GET /non-exist returns 404 but DELETE /non-exist gives 204, at that point the client would figure out your service does not fully comply with section 6.5.4 404 Not Found.

    But I want to point out that, the intended way hinted by RFC 7231, i.e. returning 404 on subsequent DELETE, shouldn't be an issue in the first place. 3x more developers chose to do that, and did you ever hear a major incident or complain caused by a client not being able to handle 404? Presumably, nope, and that is because, any decent client which implements HTTP DELETE (or any HTTP method, for that matter), would not blindly assume the result would always be successful 2xx. And then, once the developer starts to consider the error handling, 404 Not Found would be one of the first errors that comes into mind. At that point, he/she would probably draw a conclusion that, it is semantically safe for an HTTP DELETE operation to ignore a 404 error. And they did so.

Problem solved.

19 Comments

+1 "idempotency is all about the effect on the server". Meticulously answered. Well done! I'm a 404 believer for subsequent DELETE requests.
You had me at GET /non-exist returns 404 but DELETE /non-exist gives 204
This answer was very useful to make the underlying specifications clear and to bring back the focus on what the RFC says. In the end it also depends on the client (how many different parties will use it, how will they use it etc.) that is going to use these REST APIs.
-1 "So, it is written in the specs, idempotency is all about the effect on the server." I ready the specs differently. It is not the EFFECT ON THE SERVER (as-in what happens on the server), but the INTENDED EFFECT ON THE SERVER (the intention of the caller to happen on the server).
@RémyvanDuijkeren, your constructive discussion is always welcome. Regarding your comment, I do not see how your emphasis on the word "intend" would make a difference here. That sentence "A request method is considered idempotent if the intended effect on the server..." was talking about idempotency, not about the status code. While we all agree that HTTP DELETE is idempotent, my point was that the status code is irrelevant. Your other quote from HTTP PUT is also irrelevant because it was in a different context talking about the PUT representation discrepancy between client and server.
|
42

The RESTful web services cookbook is a great resource for this. By chance, its google preview show the page about DELETE (page 11):

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

8 Comments

Yes, that looks like a great resource. However, the DELETE section is not pulling up for me (it is page 23 and the preview has that redacted). Have you read this book? Do you happen to know the answer to my question?
This book is a must have for building REST (it talks in particular, not in a language).
@Craig Reading the Cookbook, it says you SHOULD return 200 OK even if you have deleted it already. However, in practice that would require the server to track all deleted resources, therefore, you CAN use 404. It goes on to say that security concerns may require you to always return 404. Page 11.
Well, the book is wrong. Idempotency doesn't imply that the status code will be the same. What's relevant is the final state of the server.
cont... it depends on your situation. PayPal returns the same code. Someone else like me, wants to know if it found it to delete it. I programmed the client side, I'll handle it how I need to handle it. In some cases I DO want to know. In other cases it doesn't matter what is returned as long as it's not there anymore. Some examples say do it this way, others say the other way. It's up to you and your situation. If you never need to care if it deleted something or not... return the same code, make your client code more simple as long as it fits into your project :)
|
26

First DELETE: 200 or 204.

Subsequent DELETEs: 200 or 204.

Rationale: DELETE should be idempotent. If you return 404 on a second DELETE, your response is changing from a success code to an error code. The client program may take incorrect actions based on the assumption the DELETE failed.

Example:

  • Suppose your DELETE operation is part of a multi-step operation (or a "saga") executed by the client program.
  • The client program may be a mobile app performing a bank transaction, for example.
  • Let's say the client program has an automatic retry for a DELETE operation (it makes sense, because DELETE is supposed to be idempotent).
  • Let's say the first DELETE was executed successfully, but the 200 response got lost on its way to the client program.
  • The client program will retry the DELETE.
  • If the second attempt returns 404, the client program may cancel the overall operation because of this error code.
  • But because the first DELETE executed successfully on the server, the system may be left at an inconsistent state.
  • If the second attempt returns 200 or 204, the client program will proceed as expected.

Just to illustrate the use of this approach, the HTTP API style guide for PayPal has the following guideline:

DELETE: This method SHOULD return status code 204 as there is no need to return any content in most cases as the request is to delete a resource and it was successfully deleted.

As the DELETE method MUST be idempotent as well, it SHOULD still return 204, even if the resource was already deleted. Usually the API consumer does not care if the resource was deleted as part of this operation, or before. This is also the reason why 204 instead of 404 should be returned.

8 Comments

The question is, what is important to the client, that it deleted the resource, or that the resource has been deleted. What if some other client deleted the resource during the saga. Do you really want to fail considering the clients objective has been achieved?
@DarrelMiller Good point. What is more important depends on the business context. But in general, I'd rather return 204 on a second DELETE attempt, even if the resource was deleted by another client. I don't want the service to fail (i.e., 404) given that the clients objective was achieved.
As others mentioned, idempotency is not what your response code is, it is what your server state is.
@Paulo Merson what code will you return if the client asks for deletion of a item that NEVER existed ? 204 ? or 404 ? If you always return 204 what is the point in checking return code ?
@frenchone If you have a way to know that the item never existed, you should return 404 in the first and subsequente DELETE attempts. If you don't, but the client program needs to know whether the item existed, you can have the client program always do a GET prior to the DELETE. GET of course will return 404 if the item doesn't exist (because it never existed or because it was deleted).
|
3

I'm going to throw 410 Gone into the mix. RFC 7231, section 6.5.4 410 Gone says

The 410 (Gone) status code indicates that access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.

So 204 for the first DELETE and 410 for the subsequent DELETEs. It's nice and consistent too, as a GET, PUT, etc will also return 410.

However, it would require the server to keep track of what has been deleted and the spec does go on to say

If the origin server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) ought to be used instead.

So, if it's valuable to keep track of deleted resources (e.g. if you need to prevent them from being re-created), 410, otherwise, 404 as recommended in this answer, or in other words "it depends".

1 Comment

I'd keep the 410 for soft-deleted resources, then. Otherwise you can't know if the resource was there at some point.
2

As far as I've observed, most developers tend to use 200 as the response code for DELETE requests, regardless of whether the resource exists or not. However, the correct approach would be to return 200 only if the operation is successful after deleting an existing record, and 404 if the resource being requested is not found. The 404 status code is specifically meant for resource not found, and not just for page not found errors.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404

Therefore, I recommend using 200 for successful operations and 404 for missing resources. It can also assist in managing the test cases to ensure proper implementation.

Comments

-1

Another alternative:

Always return 200 (OK) outputting the number of resources deleted (0 or 1).

Benefits:

  • It's consistent if you have another route that permits deleting multiple objects by search/filtering.
  • The user of your API always knows if a resource got deleted or not (and the check is trivial).
  • The status code remains the same, which feels right; at least to me.
  • The approach of returning the number of deleted documents/rows/objects (which can be 0) is common in databases.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.