RESTful undelete

Caleb picture Caleb · Dec 24, 2011 · Viewed 7.5k times · Source

It is a fairly common requirement to support undeletes or delayed/batched deletions for data services. What I'm wondering is how to implement this in a RESTful way. I'm torn between a few different options (none of which seems terribly attractive to me). Common across these different options, I believe, is the need for an API which returns all resource marked as deleted for a particular resource type.

Here are some options I've thought about and some of their pros/cons:

Options to mark resource as deleted:

  • Use HTTP DELETE to mark the resource as deleted.
  • Use HTTP PUT/POST to update deleted flag. This doesn't feel right since it maps what is essentially a deletion away from the HTTP DELETE method and into other HTTP methods.

Options when GET-ing resource marked for deletion:

  • Return HTTP Status 404 for a resource marked as deleted. Clean & transparent, but how do we tell the difference between a resource that is really deleted vs. one just marked as deleted.
  • Return HTTP Status 410. Provides way to tell the difference, but 410 technically says it "is expected to be considered permanent. Clients with link editing capabilities SHOULD delete references to the Request-URI after user approval." There may be enough wiggle room in the words "expected" and "SHOULD" here. Not sure how well 410 is supported/understood out there in clients.
  • Return HTTP Status 200 and include flag field indicating resource is deleted. This seems wierd since the idea of deleting it in the first place was because you actually wanted it to not appear. This pushes responsibility for filtering out deleted resources down to clients.

Options for responses which include this deleted resource:

  • Omit the resources makred as deleted. Clean & simple. But what if you actually want to know about deleted resources.
  • Include them along with field indicating that they are deleted. This pushes responsibility for filtering out deleted resources down to clients. It makes pagination tricky if you want to only page through active or deleted resources.

Options when updating a resource marked for deletion:

  • Use HTTP Status 404. The resource is gone right? But, how can you tell the difference between a resource marked as deleted and one actually deleted. HTTP body in 404 response could disambiguate here but then clients are left with parsing/interpreting your body to disambiguate. Maybe response header might help here? Which one? Custom header?
  • Use HTTP Status 409 with message about how resource must first be undeleted.

Options to undelete resource marked for deletion:

  • Use HTTP PUT/POST for update operation of resource and mark it as active again. This only works as long as you're not returning an HTTP 404 for the GET operation for the resource since it doesn't make since to PUT/POST to a resource that is "Not found" (404).
  • Use HTTP PUT/POST for creation operation of resource. The problem here is which data takes precedence? The data sent up in the create operation? Or the data that is being undeleted? filter it out of any other queries that would have returned it. Then, treat the HTTP PUT/POST that creates the resource as an undelete if the resource identifier points to a resource marked as deleted.
  • Separate REST path dedicated to undelete resources marked for deletion.

This is by no means an exhaustive list. I just wanted to enumerate some of the options that have been bouncing around in my head.

I know the answer to how to do this is, as usual, "it depends". What I'm curious about is what qualifications/requirements would you use to make your decision? How have you seen this implemented or implemented it yourself?

Answer

jmkeyes picture jmkeyes · Dec 24, 2011

Going by the book: RFC 2616-9.7:

  The DELETE method requests that the origin server delete the resource 
  identified by the Request-URI. This method MAY be overridden by human 
  intervention (or other means) on the origin server. 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. However, the server SHOULD NOT 
  indicate success unless, at the time the response is given, if it intends
  to delete the resource or move it to an inaccessible location.

When you DELETE a resource the server should mark the resource for deletion on it's side. It doesn't really have to delete the resource, it just can't give any guarantee that the operation has been carried out. Even so, the server shouldn't say it's been deleted when it hasn't.

  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.

If the operation is delayed, send a 202 and an entity body describing the result of the action. (Think of a poll-able "task" representing the server's deferred deletion of the resource; It could theoretically leave it forever in that state.) All it has to do is prevent the client from retrieving it again in it's original form. Use a 410 for the response code, and when the "task" finishes or the server otherwise deletes the resource, return a 404.

However, if a DELETE's semantics don't make sense for the resource in question, perhaps it's not a deletion you're looking for, but an addition state transition that alters the resource state but keeps it accessible? In that case, use a PUT/PATCH to update the resource and be done.