400 vs 422 response to POST of data
I'm trying to figure out what the correct status code to return on different scenarios with a "REST-like" API that I'm working on. Let's say I have an end point that allows POST'ing purchases in JSON format. It looks like this:
{
"account_number": 45645511,
"upc": "00490000486",
"price": 1.00,
"tax": 0.08
}
What should I return if the client sends me "sales_tax" (instead of the expected "tax"). Currently, I'm returning a 400. But, I've started questioning myself on this. Should I really be returning a 422? I mean, it's JSON (which is supported) and it's valid JSON, it's just doesn't contain all of the required fields.
400 Bad Request would now seem to be the best HTTP/1.1 status code for your use case.
At the time of your question (and my original answer), RFC 7231 was not a thing; at which point I objected to 400 Bad Request
because RFC 2616 said (with emphasis mine):
The request could not be understood by the server due to malformed syntax.
and the request you describe is syntactically valid JSON encased in syntactically valid HTTP, and thus the server has no issues with the syntax of the request.
However as pointed out by Lee Saferite in the comments, RFC 7231, which obsoletes RFC 2616, does not include that restriction:
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).
However, prior to that re-wording (or if you want to quibble about RFC 7231 only being a proposed standard right now), 422 Unprocessable Entity
does not seem an incorrect HTTP status code for your use case, because as the introduction to RFC 4918 says:
While the status codes provided by HTTP/1.1 are sufficient to describe most error conditions encountered by WebDAV methods, there are some errors that do not fall neatly into the existing categories. This specification defines extra status codes developed for WebDAV methods (Section 11)
And the description of 422
says:
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.
(Note the reference to syntax; I suspect 7231 partly obsoletes 4918 too)
This sounds exactly like your situation, but just in case there was any doubt, it goes on to say:
For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
(Replace "XML" with "JSON" and I think we can agree that's your situation)
Now, some will object that RFC 4918 is about "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" and that you (presumably) are doing nothing involving WebDAV so shouldn't use things from it.
Given the choice between using an error code in the original standard that explicitly doesn't cover the situation, and one from an extension that describes the situation exactly, I would choose the latter.
Furthermore, RFC 4918 Section 21.4 refers to the IANA Hypertext Transfer Protocol (HTTP) Status Code Registry, where 422 can be found.
I propose that it is totally reasonable for an HTTP client or server to use any status code from that registry, so long as they do so correctly.
But as of HTTP/1.1, RFC 7231 has traction, so just use 400 Bad Request
!
Case study: GitHub API
https://developer.github.com/v3/#client-errors
Maybe copying from well known APIs is a wise idea:
There are three possible types of client errors on API calls that receive request bodies:
Sending invalid JSON will result in a 400 Bad Request response.
HTTP/1.1 400 Bad Request Content-Length: 35 {"message":"Problems parsing JSON"}
Sending the wrong type of JSON values will result in a 400 Bad Request response.
HTTP/1.1 400 Bad Request Content-Length: 40 {"message":"Body should be a JSON object"}
Sending invalid fields will result in a 422 Unprocessable Entity response.
HTTP/1.1 422 Unprocessable Entity Content-Length: 149 { "message": "Validation Failed", "errors": [ { "resource": "Issue", "field": "title", "code": "missing_field" } ] }
400 Bad Request is proper HTTP status code for your use case. The code is defined by HTTP/0.9-1.1 RFC.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
https://www.rfc-editor.org/rfc/rfc2616#section-10.4.1
422 Unprocessable Entity is defined by RFC 4918 - WebDav. Note that there is slight difference in comparison to 400, see quoted text below.
This error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
To keep uniform interface you should use 422 only in a case of XML responses and you should also support all status codes defined by Webdav extension, not just 422.
https://www.rfc-editor.org/rfc/rfc4918#page-78
See also Mark Nottingham's post on status codes:
it’s a mistake to try to map each part of your application “deeply” into HTTP status codes; in most cases the level of granularity you want to be aiming for is much coarser. When in doubt, it’s OK to use the generic status codes 200 OK, 400 Bad Request and 500 Internal Service Error when there isn’t a better fit.
How to Think About HTTP Status Codes
To reflect the status as of 2015:
Behaviorally both 400 and 422 response codes will be treated the same by clients and intermediaries, so it actually doesn't make a concrete difference which you use.
However I would expect to see 400 currently used more widely, and furthermore the clarifications that the HTTPbis spec provides make it the more appropriate of the two status codes:
- The HTTPbis spec clarifies the intent of 400 to not be solely for syntax errors. The broader phrase "indicates that the server cannot or will not process the request due to something which is perceived to be a client error" is now used.
- 422 is specifically a WebDAV extension, and is not referenced in RFC 2616 or in the newer HTTPbis specification.
For context, HTTPbis is a revision of the HTTP/1.1 spec that attempts to clarify areas that were unclear or inconsistent. Once it has reached approved status it will supersede RFC2616.