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 a 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.
https://www.keycdn.com/support/422-unprocessable-entity/
Your case:
HTTP 400
is the right status code for your case from REST perspective as its syntactically incorrect to sendsales_tax
instead oftax
, though its a valid JSON. This is normally enforced by most of the server side frameworks when mapping the JSON to objects. However, there are some REST implementations that ignore newkey
in JSON object. In that case, a customcontent-type
specification to accept only valid fields can be enforced by server-side.Ideal Scenario for 422:
In an ideal world, 422 is preferred and generally acceptable to send as response if the server understands the content type of the request entity and the syntax of the request entity is correct but was unable to process the data because its semantically erroneous.
Situations of 400 over 422:
Remember, the response code 422 is an extended HTTP (WebDAV) status code. There are still some HTTP clients / front-end libraries that aren't prepared to handle 422. For them, its as simple as "HTTP 422 is wrong, because it's not HTTP". From the service perspective, 400 isn't quite specific.
In enterprise architecture, the services are deployed mostly on service layers like SOA, IDM, etc. They typically serve multiple clients ranging from a very old native client to a latest HTTP clients. If one of the clients doesn't handle HTTP 422, the options are that asking the client to upgrade or change your response code to HTTP 400 for everyone. In my experience, this is very rare these days but still a possibility. So, a careful study of your architecture is always required before deciding on the HTTP response codes.
To handle situation like these, the service layers normally use
versioning
or setupconfiguration
flag for strict HTTP conformance clients to send 400, and send 422 for the rest of them. That way they provide backwards compatibility support for existing consumers but at the same time provide the ability for the new clients to consume HTTP 422.The latest update to RFC7321 says:
This confirms that servers can send HTTP 400 for invalid request. 400 doesn't refer only to syntax error anymore, however, 422 is still a genuine response provided the clients can handle it.
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):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:
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:And the description of
422
says:(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:
(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
!400 Bad Request is proper HTTP status code for your use case. The code is defined by HTTP/0.9-1.1 RFC.
http://tools.ietf.org/html/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.
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.
http://tools.ietf.org/html/rfc4918#page-78
See also Mark Nottingham's post on status codes:
How to Think About HTTP Status Codes
Firstly this is a very good question.
400 Bad Request - When a critical piece of information is missing from the request
e.g. The authorization header or content type header. Which is absolutely required by the server to understand the request. This can differ from server to server.
422 Unprocessable Entity - When the request body can't be parsed.
This is less severe than 400. The request has reached the server. The server has acknowledged the request has got the basic structure right. But the information in the request body can't be parsed or understood.
e.g.
Content-Type: application/xml
when request body is JSON.Here's an article listing status codes and its use in REST APIs. https://metamug.com/article/status-codes-for-rest-api.php
Case study: GitHub API
https://developer.github.com/v3/#client-errors
Maybe copying from well known APIs is a wise idea: