views:

419

answers:

5

Is it to be considered good practice to reuse RFC HTTP Status codes like this, or should we be making up new ones that map exactly to our specific error reasons?

We're designing a web service API around a couple of legacy applications.

In addition to JSON/XML data structures in the Response Body, we aim to return HTTP Status Codes that make sense to web caches and developers.

But how do you go about mapping different classes of errors onto appropriate HTTP Status codes? Everyone on the team agrees on the following:

GET /package/1234 returns 404 Not Found if 1234 doesn't exist

GET /package/1234/next_checkpoint returns 400 Bad Request if "next_checkpoint" and 1234 are valid to ask for but next_checkpont here doesn't make sense...

and so on... but, in some cases, things needs to be more specific than just "400" - for example:

POST /dispatch/?for_package=1234 returns 412 Precondition Failed if /dispatch and package 1234 both exist, BUT 1234 isn't ready for dispatch just yet.


(Edit: Status codes in HTTP/1.1 and Status codes in WebDAV ext.)

+1  A: 

Actually, you shouldn't do this at all. Your use of 404 Not Found is correct, but 400 Bad Request is being used improperly. A 400 Bad Request according to the RFC is used solely when the HTTP protocol is malformed. In your case, the request is syntactically correct, it is just an unexpected argument. You should return a 500 Server Error and then include an error code in your REST result.

David Pfeffer
why a downvote?
Gregoire
Really? All it says is, “The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.” It doesn't specify if the error is in HTTP or the application-layer bit of the request.A 500 Server Error is to non-specific for requests where the client sent incorrect data. I tend to think 500 errors as things that should never happen (programming errors and the like), while 4xx series as meaning "invalid input".
Steve Pomeroy
400 series are for when the client made a mistake. 500 series are for when the server made a mistake. In these scenarios the server did not cause the error so 500 is not valid.
Darrel Miller
The "syntax" the RFC is referring to is HTTP syntax. You're looking at the *HTTP* RFC; how can it possibly be talking about an application level syntax error for a lower OSI level construct? Server error is appropriate here because the server is the one who cannot continue. The client may be at fault from an application perspective, but from an HTTP perspective it is the server's fault that the conversation is not continuing.
David Pfeffer
I'm not fully convinced that "syntax" means strictly HTTP syntax or the combined request syntax, including things like your request body. The RFC doesn't specify and the language is fairly nebulous.In practice, you'd really like to have some way of differentiating between requests that can't be fulfilled due to the server or due to an error on the client somehow. Using a 500 vs. 400 seems to make the most sense for these cases.
Steve Pomeroy
@Steve Pomeroy, you have to consider separation of layers. Would you send a TCP FIN+SYN because you didn't like an HTTP protocol transmission? In the same way, you wouldn't send an HTTP code indicating a client error when you don't like the application layer's decisions.
David Pfeffer
@David Pfeffer, Yeah, but the HTTP RFC is more loose about what the status code definitions mean. Take a look at the RFCs I cited below which use the 400 status response for their application-layer errors. After all, if you say that all application-layer client errors are to be 500 series responses then there is no simple way to transmit your own application-layer client errors without making up a new 4xx series HTTP status code. Additionally, other 4xx series codes refer to non-syntactical client errors.
Steve Pomeroy
This was kind of where the discussion in our office got stuck... Good to see your arguments though :)
conny
@David Pfeffer HTTP is an application level protocol. It's response codes are intended to be used by distributed applications to indicate application errors.
Darrel Miller
@Darrel Miller: I understand that HTTP is really an application layer protocol, I'm just saying that its a protocol on top of which other things are layered. The OP should use his own error codes in the response rather than using HTTP codes.
David Pfeffer
Pretty much the 'point' of RESTful HTTP is to provide/conform to the uniform mechanisms by which clients and servers should interact (i.e. there's nothing to add/layer on top). Applications that leverage HTTP in a RESTful way do not 'layer' on top of HTTP; they are (deliberately) constrained and governed by its architecture. Clients are driven in RESTful applications by exchanging (hypermedia) representations *through* (not on top of) HTTP.
Mike
+1  A: 

You should use 4xx series responses that best match your request when the client makes a mistake, though be careful to not use ones that are meant for specific headers or conditions. I tend to return a human-readable status message and either a plain-text version of the error as the response body or a structured error message, depending on application context.

Update: Upon further reading of the RFC, "procondition failed" is meant for the conditional headers, such as "if-none-match". I'd give a general 400 message for that instead.

Steve Pomeroy
A note regarding this, another SO thread that's relevant:http://stackoverflow.com/questions/1959947/whats-an-appropriate-http-status-code-to-return-by-a-rest-api-service-for-a-vali
Steve Pomeroy
Another thing to back up this perspective: the XCAP specification (RFC4825, and uses HTTP) uses 400 response codes when there's an XCAP client error.
Steve Pomeroy
Webdav (rfc2518), too, uses 400 response codes when there is a bad request body.
Steve Pomeroy
+4  A: 

RESTful use of HTTP means that you must keep the API uniform. This means that you cannot add domain specific methods (ala GET_STOCK_QUOTE) but it also means that you cannot add domain specific error codes (ala 499 Product Out Of Stock).

In fact, the HTTP client error codes are a good design check because if you design your resource semantics properly, the HTTP error code meanings will correctly express any errors. If you feel you need additional error codes, your resource design is likely wrong.

Jan

Jan Algermissen
So, how do things like Webdav (which uses HTTP) get away with extending it? Is it simply because it isn't HTTP (even though it uses it)?
Steve Pomeroy
Yeah - I looked at the WebDAV extensions but I consider them highly DAV-specific and something I would rather not "reuse"...
conny
Question is: HOW does one of the most common web servers get away with all these "substatus" codes when the RFC says "3DIGIT followed by space(s)"? http://support.microsoft.com/kb/943891/
conny
@Steve: WebDAV extensions are uniform. The apply to any resource. It is ok to extend HTTP but the semantics of any extension must make sense for any resource.
Jan Algermissen
@Conny: Microsoft's status codes are just plain wrong. HTTP does not allow them.
Jan Algermissen
@Conny: Keep in mind that WebDAV is not *a* specific application. It is an extension of HTTP's uniform interface. It makes a lot of sense to reuse some of these extensions (e.g 422) but some are simply breaking REST's constraints (all or PROP*) or HTTP itself (COPY, MOVE). Those I'd not reuse.
Jan Algermissen
Think about PATCH for example. That is a perfectly good extension of HTTP. Or the sometimes mentioned WATCH (or MONITOR) to do pubsub with HTTP:<code>WATCH /my/feedReply-To: http://some.org/please/send/notification/here</code>Jan
Jan Algermissen
+2  A: 

422 Unprocessable Entity is a useful error code for scenarios like this. See this question http://stackoverflow.com/questions/2190945/what-http-response-code-for-rest-service-on-put-method-when-domain-rules-invalid/2194786#2194786 for additional information.

Darrel Miller
+1  A: 

GET /package/1234/next_checkpoint returns 400 Bad Request if "next_checkpoint" and 1234 are valid to ask for but next_checkpont here doesn't make sense...

This is the wrong way to think about that URI.

URIs are opaque, so observing that parts of it are 'valid' and others are not doesn't make any sense from a client perspective. Therefore you should 'just' return a 404 to the client, since the resource "package/1234/next_checkpoint" doesn't exist.

Mike