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://docs.github.com/en/rest/overview/resources-in-the-rest-api#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.
There is no correct answer, since it depends on what the definition of "syntax" is for your request. The most important thing is that you:
Use the response code(s) consistently
Include as much additional information in the response body as you can to help the developer(s) using your API figure out what's going on.=
Before everyone jumps all over me for saying that there is no right or wrong answer here, let me explain a bit about how I came to the conclusion.
In this specific example, the OP's question is about a JSON request that contains a different key than expected. Now, the key name received is very similar, from a natural language standpoint, to the expected key, but it is, strictly, different, and hence not (usually) recognized by a machine as being equivalent.
As I said above, the deciding factor is what is meant by syntax. If the request was sent with a Content Type of application/json, then yes, the request is syntactically valid because it's valid JSON syntax, but not semantically valid, since it doesn't match what's expected. (assuming a strict definition of what makes the request in question semantically valid or not).
If, on the other hand, the request was sent with a more specific custom Content Type like application/vnd.mycorp.mydatatype+json that, perhaps, specifies exactly what fields are expected, then I would say that the request could easily be syntactically invalid, hence the 400 response.
In the case in question, since the key was wrong, not the value, there was a syntax error if there was a specification for what valid keys are. If there was no specification for valid keys, or the error was with a value, then it would be a semantic error.
422 Unprocessable Entity Explained Updated: March 6, 2017
What Is 422 Unprocessable Entity?
A 422 status code occurs when a request is well-formed, however, due
to semantic errors it is unable to be processed. This HTTP status was
introduced in RFC 4918 and is more specifically geared toward HTTP
extensions for Web Distributed Authoring and Versioning (WebDAV).
There is some controversy out there on whether or not developers
should return a 400 vs 422 error to clients (more on the differences
between both statuses below). However, in most cases, it is agreed
upon that the 422 status should only be returned if you support WebDAV
capabilities.
A word-for-word definition of the 422 status code taken from section
11.2 in RFC 4918 can be read below.
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.
The definition 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.
400 vs 422 Status Codes
Bad request errors make use of the 400 status code and should be
returned to the client if the request syntax is malformed, contains
invalid request message framing, or has deceptive request routing.
This status code may seem pretty similar to the 422 unprocessable
entity status, however, one small piece of information that
distinguishes them is the fact that the syntax of a request entity for
a 422 error is correct whereas the syntax of a request that generates
a 400 error is incorrect.
The use of the 422 status should be reserved only for very particular
use-cases. In most other cases where a client error has occurred due
to malformed syntax, the 400 Bad Request status should be used.
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 send sales_tax instead of tax, 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 new key in JSON object. In that case, a custom content-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 setup configuration 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:
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).
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 - Failed the request validation like if the data is missing, if it has a wrong type, etc. so it is given a status of 400.
422 - Passes the request validation, but failed the operation process, because the the request data, or part of it is giving an error to the to the operation, but is handled, and given a status of 422.
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
Related
As far as I understand it, in addition to returning a 404 Not Found for unknown endpoints, a REST API should also return a 404 in the following cases:
requesting a resource with an ID that does not exist in the path: route /users/{id} exists, but /users/123456 does not exist
requesting a resource with an ID that does not exist in the query parameters: route /search exists, but /search?user=123456 returns a 404 if the user does not exist (I asked a similar question a few years ago)
Now what about the use case where an endpoint accepts a JSON object with a number of fields, one of them being the ID of a user that does not exist:
POST /makeReservation HTTP/1.1
...
{
"userId": 123456,
...
}
Should this return a 404 as well, or is this considered a different kind of error (validation error?) in this case?
As far as I understand it
I'd say your current understanding is a little bit more complicated than it should be.
404 Not Found means:
The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
In case "target resource" is unclear, we can review the specification of the Request Line.
request-line = method SP request-target SP HTTP-version CRLF
The request-target identifies the target resource upon which to apply the request, as defined in Section 5.3.
In other words, 404 says "there is a problem with the spelling of the request-target".
Therefore, it is misleading to suggest that there is a problem with the request-target, when the actual problem is in the request body.
The error code you probably want for this case is 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.
IANA's HTTP Status Code Registry is a good place to look when you are sure that there should be a standardized code for your use case, but you are having trouble guessing which specification describes it.
it's part of WebDAV and I'm not sure how correct it is to use it for other applications?
TL;DR: it's correct to use it for other applications.
The HTTP specification defines the process by which new codes can be added to the status code registry, and that process has been followed for the WebDAV codes. So we can be confident that the meaning of 422 won't be replaced by some other semantic (for compatibility, status codes are retired -- see status code 306.)
The definition of 422 in the WebDAV specification is not WebDAV specific.
Furthermore, the behavior of clients that are not aware of the WebDAV specification is described in RFC 7231
a client MUST understand the class of any status code, as indicated by the first digit, and treat an unrecognized status code as being equivalent to the x00 status code of that class, with the exception that a recipient MUST NOT cache a response with an unrecognized status code.
You can also review appendix B of the WebDAV specification.
(As a side note, I think your concern is reasonable -- WebDAV methods are much harder to re-use outside of that context.)
Update 2022-07-12: the IANA registered reference for status code 422 is now RFC 9110 (HTTP Semantics). We no longer need be concerned when we use that status code outside of a WebDAV context.
I am trying to implement some PATCH requests in our software(following https://www.rfc-editor.org/rfc/rfc7396). The resources have some fields which must not be modified, so I am thinking to return some error status code when such fields appear in HTTP JSON request body. 400 seems a bit too generic (I am using it for validation errors e.g. email format and the like). Perhaps there is some other status code used in such situations?
There's a code for that . . . 8-)
403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Furthermore, 403 is suitable even if there are no credential problems.
This is explained in RFC7231 Section 6.5.3:
a request might be forbidden for reasons
unrelated to the credentials
RFC 7231 section 8.2 a status code registry, so that's the place to start.
This is clearly a problem with the request; something the client might be able to fix, so an entry from the 4xx class is appropriate.
405 Method Not Allowed is wrong for the case you describe -- a different merge patch document would be accepted by this resource, but not the one that is present.
403 Forbidden is wrong, as it communicates a problem related to credentials, but you are describing a problem with payload.
409 Conflict could be reasonable...
the request could not be completed due to a conflict with the current state of the target resource.
I don't see any reason that the conflict can't be in an immutable part of the "current state".
But I think your best bet is 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.
Another good resource to consider is the HTTP Patch specification. RFC 5789 enumerates a number of reasons that a patch might fail, and what code would be appropriate to use in each context. You can decide for yourself whether you think those distinctions are appropriate in your circumstances.
There may also be more specific errors like "Conflicting State" that could be signaled with this status code, but the more specific error would generally be more helpful.
Using a following API:
feed?url=XXX
Validations performed on the parameter url:
If missing: 400 Bad Request
If empty/invalid URL: 422 Unprocessable Entity
If URL don't point to a valid RSS/Atom feed: 422??
What status error should be returned for the 3.?
Unlike validation 2., it is not possible to check the 3. without fetching data and trying to parse it, so raw user data can't be directly validated.
I was thinking about 422 Unprocessable Entity because it is related to validation even if is not directly the data (url) but the reference of this data (content of the url).
What is your opinion?
422 is inappropriate for #2 and #3. It relates to the server understanding the Content-Type header, but the actual content in the HTTP request body could not be interpreted.
I think you could make the argument that 502 Bad Gateway is appropriate here. It's a bit weird because the problem is both user error (incoming url parameter, so a 4xx code), but also it's kind of happening on the server, and in particular an origin server (which makes sense as a 5xx and specifically 502).
But if in this context you strictly consider this an issue that the client caused (bad input in the url) and not server-side, then I would say that there's not a specific enough error code for this, and you should probably just stick to 400 for all of them.
And maybe.. perhaps you can make the argument that 409 might work here. A 409 can used in a case where:
There is nothing in particular wrong with the HTTP request perse.
But the state of another resource is causing the request to fail.
Typically that 'other resource' lives in the same system, but I don't see why the external Atom feed could also not be considered as conflicting.
Because if the Atom feed on the external server is 'fixed', then the original HTTP request that the user made will now work. So a 409 kind of is appropriate here.
It is unclear to me when you should and should not return a HTTP 412: Precondition Failed, error for a web service? I am thinking of using it when validating data. For example, if a client POST's XML data and that data is missing a required data element, then responding with a 412 and a description of the error.
Does that align with the spirit of responding with an HTTP 412, or should something else be used (e.g. another http error code or web application exception)?
If you look at RFC 2616 you'll see a number of request headers that can be used to apply conditions to a request:
If-Match
If-Modified-Since
If-None-Match
If-Range
If-Unmodified-Since
These headers contain 'preconditions', allowing the client to tell the server to only complete the request if certain conditions are met. For example, you use a PUT request to update the state of a resource, but you only want the PUT to be actioned if the resource has not been modified by someone else since your most recent GET.
The response status code 412 (Precondition Failed) is typically used when these preconditions fail.
Your example sounds like an invalid request (i.e. the client has submitted data that is invalid because of missing values). A status code of 400 (Bad Request) is more appropriate here IMO.
412 is reserved for cases where the request is conditional, and the condition isn't met.
For your use case, 422 Unprocessable Entity is a good match.
Your best bet would be to avoid 412. In practice most web services that I've used send a 400 code (Bad Request). A lot of frameworks have built-in support for 400 too and your clients will appreciate a more common error code. Often times, especially with REST interfaces, a simple "message" or "error" element is returned with a description.
What is the most appropriate response code to return when using the PUT method to update a resource, and the request contains some data that would invalidate the domain rules?
For example, a customer resource must have a name specified. If an agent tries to issue a PUT without supplying a name I don't want to update the resource, and I want to tell the caller that they need to supply a name.
What HTTP response code?
How about 422?
"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."
RFC 4918, Section 11.2
The response code is not related to the http method in this case. You should return the same status code as if it had been a POST request. I'd say you should use 400 or 409 (Note: See further discussion of the difference between the two in the comments).
I would return a 400. Strictly, this is for "malformed syntax" (not invalid data), but in practice the YouTube, Twitter, etc. use it for more generally "bad" requests.