I'm at a bit of a crossroads with some API design for a client (JS in a browser) to talk to a server. We use HTTP 409 Conflict to represent the failing of an action because of a safety lock in effect. The satefy lock prevents devs from accidentally making changes in our customers' production systems. I've been tasked with handling 409s a bit more gracefully on the client to indicate why a particular API call failed.
My solution was to wrap the failure handlers of any of our AJAX calls which will display a notification on the client when something fails due to 409 – this is all fine and works well alongside other 4XX and 5XX errors which use the same mechanism.
A problem has arisen where one of our route handlers responds with 409s when encountering a business logic error – my AJAX wrapper reports that the safety lock is on, whilst the client's existing failure handler reports what (it thinks) the problem is based on the body of the response. A simple solution would be to change either the handler's response or the status code we use to represent the safety lock.
Which brings me to my crossroad: should HTTP status codes even be used to represent business logic errors? This question addresses the same issue I am facing but it did not gain much traction. As suggested in the linked answer, I'm leaning towards using HTTP 200 OK with an appropriate body to represent failure within the business logic.
Does anyone have any strong opinions here? Is anyone able to convince me this is the wrong way to represent failure?
Best Answer
Kasey covers the main point.
The key idea in any web api: you are adapting your domain to look like a document store. GET/PUT/POST/DELETE and so on are all ways of interacting with the document store.
So a way of thinking about what codes to use, is to understand what the analogous operation is in a document store, and what this failure would look like in that analog.
2xx is completely unsuitable
5xx is also unsuitable
In this case, the server didn't make a mistake; it's aware that you aren't supposed to modify that resource that way at this time.
Business logic errors (meaning that the business invariant doesn't allow the proposed edit at this time) are probably a 409
Note this last bit -- the payload of the 409 response should be communicating information to the consumer about what has gone wrong, and ideally includes hypermedia controls that lead the consumer to the resources that can help to resolve the conflict.
And I would point to this as the problem; your implementation at the client assumed that the status code was sufficient to define the problem. Instead, your client code should be reviewing the payload, and acting on the information available there.
That is, after all, how a document store would do it
The same approach with a
400 Bad Request
would also be acceptable; which roughly" translates to "There was a problem with your request. We can't be bothered to figure out which status code is the best fit, so here you go. See the payload for details."The WebDAV specification includes this recommendation
I don't believe that's quite a match (although I agree that it sheds some doubt on
400
as an alternative). My interpretation is that422
means "you've sent the wrong entity" where409
is "you've sent the entity at the wrong time".Put another way,
422
indicates an issue with the request message considered in isolation, where409
indicates that the request message conflicts with the current state of the resource.Ben Nadal's discussion of 422 may be useful to consider.