89

My question is quite a generic one about HTTP status code when a DELETE is impossible on the resource (but not regarding user's rights).

We have a RESTful API on a type of resource.

The DELETE method is authorized on the resource however under some conditions a resource cannot be deleted (if there are data binded to this resource).

What is the correct HTTP status code to return to the client in this situation?

Here are some of the possibilities I gathered and why it seems inappropriate in my case :

  • 403 (Forbidden) : Seems mostly related with user's rights.
  • 405 (Method Not Allowed) : Seems like the API is not designed to respond to this method for this type of resource.
  • 409 (Conflict) : Seems appropriate but the client should have the possibility to resolve the conflict with the API but that's not the case here.

Update : The data binding that prevents the resource to be deleted cannot be changed via the REST API. However the resource can be "freed" via other way as the database from which the data comes from is also accessed by other apps that may change the state of a resource (an SQL DELETE in the DB can always do that).

Matt
  • 3,422
  • 1
  • 23
  • 28
  • 3
    It's all rather debatable. I'd tend towards 405 if each resource has a unique URL, e.g. `DELETE /things/42`. If it's just `DELETE /things?id=42` that may not be appropriate, as you say. If in doubt, 400. If really in doubt, `418 I'm a teapot`. ;) – deceze Aug 04 '14 at 15:51
  • @deceze Sadly, IANA has not (yet!) formally recognized `418 I'm a teapot` as a valid response code. :-( – Eric Stein Aug 05 '14 at 13:00
  • @Eric That's absolutely no reason not to use it. :o) – deceze Aug 05 '14 at 13:02
  • 1
    @deceze yeah REST questions seem to be often debatable :) – Matt Aug 05 '14 at 13:23
  • @Matt I'd try not to overthink it. In the end, any client using this API will be customised to it anyway. As long as it's consistent within itself and well documented, there's hardly a difference between a 405 and a 409. – deceze Aug 05 '14 at 13:25
  • I think this one boils down to whether your interpretation and expected clients would treat 405 as permanent or semi-permanent. If so, 405 probably isn't best, 409 instead. Otherwise I can see a case for either one. – E-Riz Aug 05 '14 at 13:25
  • Lots of good answers here. In case it helps others out with a similar need: in *certain* situations, [422 might be a good option](https://www.bennadel.com/blog/2434-http-status-codes-for-invalid-data-400-vs-422.htm) – rinogo Dec 22 '16 at 20:02

2 Answers2

70

I'd say 409 is the most appropriate, given it's wording in the RFC:

The 409 (Conflict) status code indicates that the request could not be completed due to a conflict with the current state of the target resource. This code is used in situations where the user might be able to resolve the conflict and resubmit the request. The server SHOULD generate a payload that includes enough information for a user to recognize the source of the conflict.

(emphasis mine)

Based on my understanding of the description in the question, the reason for DELETE not being allowed is exactly a conflict with the current state of the target resource. As indicated in the RFC, the response payload can give an indication of the reason and, optionally, the user might be able to resolve it. I don't see anything in the spec that makes 409 inappropriate just because the API doesn't offer a conflict resolution possibility.

E-Riz
  • 31,431
  • 9
  • 97
  • 134
  • 4
    For me, the key sentence is " This code is used in situations where the user might be able to resolve the conflict and resubmit the request." If there's no chance of a conflict ever being resolved, this sentence implies that 409 is not the correct code. – Eric Stein Aug 04 '14 at 17:27
  • 4
    I see the word "might" and read that to mean that's an optional condition of using 409. I do agree with your other comment, however, that if the resource can never be "freed" from it's "data binding" then 405 would be appropriate. Let's see what OP says... – E-Riz Aug 04 '14 at 17:30
  • @E-Riz, In my situation the resource cannot be unbound via the API. However the resource can be "freed" via other way as the database from which the data come from is also accessed by other apps that may change the state of a resource (an SQL DELETE in the DB can always do that). From what I understand, 409 means that the conflict can be resolved **VIA** the API Rest (and not via other ways). – Matt Aug 05 '14 at 08:13
  • 1
    Look at the 409 description I quoted above - there's nothing about *how* the conflict can be resolved. What, specifically, about that description doesn't apply to your situation? – E-Riz Aug 05 '14 at 13:02
  • @E-Riz Ok, you convinced me :) I guess if the resource state can change by any way, then we shouldn't use `405` but `409` as long as you specify in the body the reason of the conflict but not necessary the way to resolve it. – Matt Aug 05 '14 at 13:36
  • This is close but does not fully answer the asked question. it asks about when a DELETE is possible, some more research and tweaking may lead you onto the correct path. – Llama Feb 14 '23 at 19:32
27

A 409 Conflict response is definitely wrong if the client can't resolve the conflict and delete the request later. That is, unless the resource has state tracking whether it can be deleted or not, 409 Conflict is not a good fit.

A 403 Forbidden doesn't necessarily mean not authorized:

However, a request might be forbidden for reasons unrelated to the credentials.
   -- RFC 7231

The implication is usually there, though. You can use this code, but it may cause some confusion. It'll be especially tricky if the method actually requires authorization also - you'll need a code or something in the response indicating whether the failure was related to authorization or the resource being non-deletable.

I think that 405 Method Not Allowed is the correct way to go.

The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource.
   -- RFC 7231

The method DELETE is not supported for this resource. That sounds exactly like what you're describing. The HTTP spec doesn't really have a concept of a type of resource - just a resource. It happens that people group individual resources under the same endpoint for sanity, but that's just a convenience for developers and users. As far as the HTTP spec is concerned, /widgets/12 and /widgets/15 and /widgets/3453 are three different resources. The fact that the same object represents all three of those resources on the server is completely irrelevant. I think that's the "type" you're thinking of, but to HTTP that's just an implementation detail.

Community
  • 1
  • 1
Eric Stein
  • 13,209
  • 3
  • 37
  • 52
  • 11
    I'm not so sure that 405 is the best response in this case, mostly because it is cacheable by default. So a client would receive the 405 and cache it, thus "assuming" the Not Allowed result is a static or permanent response. Given the OP's description, however, the deletability of the resource could change. If the response is 405, how is the client to know that? – E-Riz Aug 04 '14 at 17:05
  • I should also mention that I do realize the response can indicate it's non-cacheable. However, even though the spec doesn't explicitly say so, it just feels like 405 is a more permanent response (and I'd not be surprised at clients that treat it as such) than 409. To me it violates the Principle of Least Surprise in this particular situation. – E-Riz Aug 04 '14 at 17:16
  • @E-Riz The key point is whether or not the conflict can be resolved. I was reading the OP's summary and saw "Seems appropriate but the client should have the possibility to resolve the conflict with the API but that's not the case here". However, he may contradict that earlier in his question - assuming that the bound data can be unbound, the conflict can be resolved. I would prefer 409 if the conflict were resolvable. So we may agree or disagree pending further qualification of the question. – Eric Stein Aug 04 '14 at 17:24
  • Thanks @EricStein, I think in my case 405 is correct cause there is no way to resolve the conflict via the API. – Matt Aug 05 '14 at 08:02
  • @EricStein I added some details in the questions. – Matt Aug 05 '14 at 08:28
  • This should be the accepted response. 409 seems to have been designed mainly for when implementing optimistic concurrency, i.e. the conflict is between two different versions of the same object (like a merge conflict in git). The last sentence in RFC 7231 says it all IMO: _"However, a request might be forbidden for reasons unrelated to the credentials."_ – slashCoder Mar 19 '19 at 22:06