114

Say that I have a REST endpoint that takes an integer as a parameter:

/makeWaffles?numberOfWaffles=3

In this case, I want the number to be positive because I can't make a negative number of waffles (and requesting 0 waffles is a waste of time). So I want to reject any request that does not contain a positive integer. I also want to reject a request that exceeds some maximum integer (let's say for now that it's MAX_INTEGER).

In the event that someone requests a non-positive number of waffles, should I return an HTTP 400 (Bad Request) status? My initial thought is yes: it is not a valid number for me to complete the request. However, the RFC doesn't mention business rules as a reason to throw it:

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

A business rule doesn't fall under any of those three examples. It's syntactically correct, it's properly framed, and it's not deceptive request routing.

So should I return an HTTP 400 (Bad Request) status if a parameter is syntactically correct, but violates a business rule? Or is there a more appropriate status to return?

2

5 Answers 5

106

This is a great question, and still highly relevant given the historical context (and seemingly contradictory definitions) of the HTTP return codes. Even among the answers to this question there are conflicting definitions. This can be clarified by moving chronologically.

RFC 2616 (June 1999)

10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.

As of this RFC, this status code specifically applied only to syntactically invalid requests. There was a gap in the status codes for semantic validation. Thus, when RFC 4918 came around, a new code was born.

RFC 4918 (June 2007)

11.2. 422 Unprocessable Entity

The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

422 Unprocessable Entity was created to fill the gap of semantic validation in the original specification of the 4xx status codes. However, another relevant RFC came about in 2014 which generalized 400 to no longer be specific to syntax.

RFC 7231 (June 2014, explicitly obsoletes RFC 2616)

6.5.1. 400 Bad Request

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

Note that the 422 description says that the reason 400 is inappropriate is because 400 (as of RFC 2616) should be returned only for bad request syntax. However, as of RFC 7231, the strict syntax-error definition no longer applies to 400.

Back to the question at hand: While 422 is technically more specific, given this context, I could see either 400 or 422 being used for semantic validation of API parameters. I'm hesitant to use 422 in my own APIs because the definition of 422 is technically outdated at this point (although I don't know if that's officially recognized anywhere). The article referenced in Fran's answer that encourages the use of 422 was written in 2012, two years before RFC 7231 clarified HTTP 400. Just be sure to standardize on one or the other.

55

I read the first answer and didn't really agree with it because, at least in my reading, a bad request (400) means, "I can't even handle your request because something is fundamentally wrong." And I found this post which makes the case for returning a 422.

from IETF

422 Unprocessable Entity (WebDAV; RFC 4918) The request was well-formed but was unable to be followed due to semantic errors

This seems like a more appropriate response since your request is well-formed, but doesn't pass your validation rules.

4
  • 5
    Ive heard it described as "400 means bad syntax, 422 means bad semantics."
    – cbojar
    Aug 24, 2016 at 20:44
  • 43
    All the x00 codes are "catch all" generic codes. A 400 is not inappropriate, just less specific.
    – Jack
    Aug 24, 2016 at 21:11
  • 1
    Good answer, but the ansewer given by @GoFree makes more sense for me.
    – Ewerton
    Aug 30, 2017 at 14:30
  • 2
    There is a really strong case for returning codes that everyone knows. Absolutely everyone will need to look up 422, and I'll bet that most still won't know what to make of it.
    – sylvanaar
    Feb 26, 2018 at 17:11
20

No, you should not. HTTP codes are meant for the HTTP layer of your application. Business rules is completely different layer and is application specific, so you need to come up with your own "protocol".

Imagine an apocalypse happens and you have to switch from HTTP protocol to using Pigeons. Pigeons don't have any return codes, so you would need to change your business layer to accomodate for that. But your business has not really changed in any way so you shouldn't need to change business layer. It shows a tight coupling between those two layers (transport and business).

Back to the question: What you should do is return "200 OK" with a body describing what happened with the request. The specification clearly says so:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1.

200 OK

The request has succeeded. The information returned with the response is dependent on the method used in the request, for example

POST an entity describing or containing the result of the action;

Has your HTTP request succeeded? Yes it has, the web server knows what to do with that request (e.g. pass it on to the server part of your application). Web server then passes this request to the server part of your application, which takes the POSTed data, processes them (validates them in your case) and returns a normal answer (in the body of an HTTP response) to the client part of your application. This answer from the server part of application can be either "Great, the data you sent me are valid" or "I'm sorry, the data you sent are not valid". And it is up to your client part of application to understand what the answer means.

PS: "400 Bad Request" means, that the web server did not understand what you want from it. It means that your server part of your application did not even receive the request. Or at least that's what it's meant to mean :-)

EDIT: I just realized, that you're doing GET request, not POST. This is a bad idea because GET should not change the state of the application. GET is supposed to simply retrieve data from the server. But in your request you are actually changing the state of the application, so you should really be using POST.

12
  • 2
    Yes, returning 404 in that case is fine. I'm not saying that server should always send 200 OK with an explanation in the body.
    – GoFree
    Mar 7, 2017 at 23:27
  • 3
    @Thomas Lauria I haven't seen a proper implementation of RESTFUL API yet. However, REST API is a buzzword today so every company has to use it (the word, not the technology) without actually understanding the concept behind it. So yes, it's being used in a wrong way everywhere. What programmers usually create is not a REST API, but HTTP API, or API OVER HTTP. Actually one of the few good RESTFUL implementations is the HTTP itself :)
    – GoFree
    Feb 15, 2019 at 10:56
  • 1
    If a server responds a 2XX, I expect the success case. Regardless of the type of error, request or server-side, I never expect the 2XX range but rather 4XX or 5XX. I have worked with api returning 200 OK for error cases, and it is a pain to parse them then.
    – k0pernikus
    Jun 11, 2019 at 12:51
  • 3
    Yes, you are correct to expect that the request succeeded. But on a Transportation Layer! Because HTTP status code is part of transportation protocol (as the acronym HTTP implies). Not on a Business Layer. A Post Office will not tell you if your tax return form inside the envelope is valid. It will only tell you if the address on the envelope is valid. Post Office deals with transportation of the envelope, just like HTTP, not with the content of the envelope.
    – GoFree
    Jul 2, 2019 at 14:49
  • 5
    Just adding more weight to this, if the HTTP layer has no problem with the data then you shouldn't be sending a HTTP error to indicate an error. This causes huge problems when you're trying to debug errors, because you've used your 400 to validate your business logic, what code do you now use to validate your transport layer? Jan 15, 2020 at 15:20
10

Yes, input that doesn't follow the implied contract of the endpoint is "something perceived to be a client error", and should return 400.

The exceptions to this is if the business rule is security related (then 401 Unauthorized or 403 Forbidden would be better). Alternatively, if sending a 400 would leak information about something's existence, and then a 404 Not Found may be more appropriate.

1
  • “Forbidden” = nobody is ever allowed access. “Unauthorised” = you will be allowed access with the right authorisation. And both have precedence to “not found”. “Unauthorised” gives no information that the resource exists. Status 400 “bad request” - any server anywhere should return the same status. Doesn’t give you any information about the server state. The server has no idea what you want, so it cannot even return 401 or 403.
    – gnasher729
    Oct 27 at 8:51
-2

Not sure that all would agree, but we are using 409 - Conflict. Many state the 409 is more of a conflict with system state, but we accepted the interpretation that a conflict of data values being outside of accepted range is fixable by the requester and an acceptable use of 409. 422 I think would be reasonable as the request is correctly formed but cannot be processed as requested. I opine however if you do not wish to implement a host of replies, just giving a 400 is still acceptable.

1
  • 6
    409 means "the state you're trying to put this in is in conflict with the state another client is trying to put this in", it's for blocking concurrent writes (using ETags, for example)
    – Jack
    Aug 24, 2016 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.