37

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.)

Community
  • 1
  • 1
conny
  • 9,973
  • 6
  • 38
  • 47

5 Answers5

25

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
  • 4,930
  • 4
  • 26
  • 39
  • 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 Mar 04 '10 at 17:23
  • Yeah - I looked at the WebDAV extensions but I consider them highly DAV-specific and something I would rather not "reuse"... – conny Mar 04 '10 at 17:53
  • 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 Mar 04 '10 at 17:55
  • @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 Mar 04 '10 at 18:37
  • @Conny: Microsoft's status codes are just plain wrong. HTTP does not allow them. – Jan Algermissen Mar 04 '10 at 18:38
  • 3
    @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 Mar 04 '10 at 18:41
  • 1
    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: WATCH /my/feed Reply-To: http://some.org/please/send/notification/here Jan – Jan Algermissen Mar 04 '10 at 18:43
  • PATCH is redundant; it solves a perceived problem with PUT that actually does not exist in RFC 2616. – wprl May 17 '14 at 12:05
  • Hi wprl, which problem is PATCH solving that actually does not exist? – Jan Algermissen May 18 '14 at 12:55
20

422 Unprocessable Entity is a useful error code for scenarios like this. See this question what http response code for rest service on put method when domain rules invalid for additional information.

Community
  • 1
  • 1
Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
5

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
  • 3,342
  • 1
  • 17
  • 15
4

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
  • 10,071
  • 6
  • 34
  • 37
  • 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 Mar 04 '10 at 16:35
  • 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 Mar 04 '10 at 17:16
  • Webdav (rfc2518), too, uses 400 response codes when there is a bad request body. – Steve Pomeroy Mar 04 '10 at 17:18
-1

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
  • 38,869
  • 30
  • 127
  • 202
  • 5
    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 Mar 04 '10 at 15:54
  • 20
    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 Mar 04 '10 at 15:54
  • 4
    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 Mar 04 '10 at 15:56
  • 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 Mar 04 '10 at 16:24
  • @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 Mar 04 '10 at 17:03
  • @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 Mar 04 '10 at 17:46
  • 1
    This was kind of where the discussion in our office got stuck... Good to see your arguments though :) – conny Mar 04 '10 at 17:57
  • 3
    @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 Mar 04 '10 at 22:07
  • @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 Mar 05 '10 at 03:45
  • 7
    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 Mar 05 '10 at 10:54
  • 1
    All very nice, but how is a client to know if the payload of that 4xx is hypermedia they expect or the hypermedia of tomcat reporting that the URL wasn't defined? – bmargulies May 11 '11 at 21:30