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?
Should HTTP status codes be used to represent business logic errors on a server?
rest;api;web
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 unsuitableThe 2xx (Successful) class of status code indicates that the client's  request was successfully received, understood, and accepted.5xx is also unsuitableThe 5xx (Server Error) class of status code indicates that the server is aware that it has erredIn 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, is probably a 409The 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.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.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.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 409  Conflictyour proposed change has been declined because ${REASON}.  The following resolution protocols are available: ${LINKS[@]})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.