Undo an HTTP Delete request

It's been over a year since this article was last updated. The information below might be outdated. Please contact the author for more.


How many times has CTRL+Z saved your life? Have you ever stopped to think that the consumer of your API could possibly want to undo some operations?

Today @ardalis started an interesting discussion on Twitter by raising a question about what kind of response a successful HTTP Delete operation should return.

Take a look yourself:

Most people who commented on this post tended to follow the suggestion of the original HTTP/1.1 specification as accurately as they should, which clearly says:

A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, 202 (Accepted) if the action has not yet been enacted, or 204 (No Content) if the action has been enacted but the response does not include an entity. See: RFC 2616 Fielding, et al.

And I agree with most of the comments, especially with the specification. However, I don’t know about you, but for a long time I miss a status code that is more appropriate for returns for both DELETE, PUT and PATCH.

I’m not proposing a change to the specification, who am I? I just feel that it may be possible to use the return codes more usefully and accurately. The most up-to-date specification suggests, for example, that there may be a corresponding DELETE request for each POST and PUT action. But why not the other way around too? Look at what the specification says:

For example, a resource that was previously created using a PUT request, or identified via the Location header field after a 201 (Created) response to a POST request, might allow a corresponding DELETE request to undo those actions. See: https://tools.ietf.org/html/rfc7231#section-4.3.5

As you can see in my comments in the discussion, among the things that I defended in my comments — and I don’t own the lifetime truth — are the use of the 410 GONE status code and the possibility to undo the DELETE operation as well. And this is what I want to show with the following code examples.

Show me the code!

Listing 1. Delete method.

Note that in the code in Listing 1 above I have a model that implements a generic type and that already has a default expiration time for the cache. In addition, I’m using MongoDB and managing the generation of unique identifiers via code. Thus, when undoing the operation and returning the object to the database, it’s possible to keep the same unique identifier previously generated for it.

Listing 2. Undo action.

If no object is found in the cache, a 410 GONE code is returned. Otherwise, the object is saved again in the database and then there is a 201 CREATED return with the corresponding Dto (Data Transfer Object).


You don’t need to use the Unity of Work pattern, in-memory cache or Automapper in order to implement this concept that I just presented. This was just a pseudo code that I already had here to use as an example. May it serve only as an inspiration for you to implement your own solution in order to take better advantage of the status codes that we have in the official specification.

Thank you for your time reading this!


Last edited on Apr, 19, 2020 at 4:11 pm