Which HTTP status code to use to reject a PUT due to optimistic locking failure

10,318

From your link to the spec:

If none of the entity tags match, or if "*" is given and no current entity exists, the server MUST NOT perform the requested method, and MUST return a 412 (Precondition Failed) response. This behavior is most useful when the client wants to prevent an updating method, such as PUT, from modifying a resource that has changed since the client last retrieved it.

Because the spec requires an HTTP 412 (indeed it uses "MUST"), and because it's clear that they accounted for precisely the use case under discussion, an HTTP 412 seems like the proper response code.

412 is pretty reasonable anyway. The request says to do the update conditionally. The 412 says that the condition failed, so the service won't do it. Especially since 412 is a good match for the concept of conditional requests; 409 would seem to attach to a specific sort of refusal, which may or may not be conditional in nature. For example, I could see a service returning a 409 in response to an unconditional request to POST something with an internal conflict.

But see the following, also from the spec:

10.4.10 409 Conflict

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.

Anyway the spec seems to require a 412 in conditional request contexts, while suggesting that version conflicts are a key driver for 409s. It might be that the 409 would be used where the version conflict occurs as part of an unconditional request.

Share:
10,318

Related videos on Youtube

norgence
Author by

norgence

Spring Data Project Lead @ Pivotal, Java Champion, OpenSource enthusiast, all things Spring, data, DDD, REST, software architecture, drums & music... Soul Power! https://spring.io/team/ogierke

Updated on November 25, 2022

Comments

  • norgence
    norgence over 1 year

    Assume I'd like to implement some kind of optimistic locking and use ETags to indicate the most up to date resource state. This means, clients will use an If-Match header when PUTting for an update.

    According to the HTTP spec, the server has to return 412 Precondition failed if the ETag provided for the If-Match header doesn't match the current state of the resource.

    However, 409 Conflict seems to be closer to what I want to express semantically, especially as it gives guidelines what to include in the response.

    Is it terribly wrong to rather return 409 in case of a failure to match an ETag provided in an If-Match header?

    • Papasmile
      Papasmile over 10 years
      One key is that 409 assumes "situations where it is expected that the user might be able to resolve the conflict and resubmit the request."
    • norgence
      norgence over 10 years
      I'd be in favor of 409 anyway if not the spec was requiring 412 for precondition violations :/.
    • Papasmile
      Papasmile over 10 years
      Also consider "If the request would, without the If-Match header field, result in anything other than a 2xx or 412 status, then the If-Match header MUST be ignored. "
    • norgence
      norgence over 10 years
      That's a tricky one, because the request without the header would essentially mean "store no matter what" as there's no way to find out about the conflict. So in turn, it of course would result in a 200 then. Actually, it might even be a valid situation of the client to decide to coercively PUT and override the resource state on the server .
  • Jimbo
    Jimbo over 3 years
    Why not 428? - status code indicates that the origin server requires the request to be conditional. Its typical use is to avoid the "lost update" problem, where a client GETs a resource's state, modifies it, and PUTs it back to the server, when meanwhile a third party has modified the state on the server, leading to a conflict. By requiring requests to be conditional, the server can assure that clients are working with the correct copies. Responses using this status code SHOULD explain how to resubmit the request successfully. For example: HTTP/1.1 428 Precondition Required