views:

2416

answers:

8

I'm looking for guidance on good practices when it comes to return errors from a REST API. I'm working on a new API so I can take it any direction right now. My content type is XML at the moment, but I plan to support JSON in future.

I am now adding some error cases, like for instance a client attempts to add a new resource but has exceeded his storage quota. I am already handling certain error cases with HTTP status codes (401 for authentication, 403 for authorization and 404 for plain bad request URIs). I looked over the blessed HTTP error codes but none of the 400-417 range seems right to report application specific errors. So at first I was tempted to return my application error with 200 OK and a specific XML payload (ie. Pay us more and you'll get the storage you need!) but I stopped to think about it and it seems to soapy (/shrug in horror). Besides it feels like I'm splitting the error responses into distinct cases, as some are http status code driven and other are content driven.

So what is the SO crowd recommendation? Good practices (please explain why!) and also, from a client pov, what kind of error handling in the REST API makes life easier for the client code?

+10  A: 

So at first I was tempted to return my application error with 200 OK and a specific XML payload (ie. Pay us more and you'll get the storage you need!) but I stopped to think about it and it seems to soapy (/shrug in horror).

I wouldn't return a 200 unless there really was nothing wrong with the request. From RFC2616, 200 means "the request has succeeded."

If the client's storage quota has been exceeded (for whatever reason), I'd return a 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 for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.

This tells the client that the request was OK, but that it failed (something a 200 doesn't do). This also gives you the opportunity to explain the problem (and its solution) in the response body.

What other specific error conditions did you have in mind?

Rich Apodaca
Should I include my detailed error message in the body, ie. an XML code/string pair? How are clients best dealing with this? For instance I know C# WebRequest based clients would throw 'Bad Request' or 'Forbidden' and not give the response body.
Remus Rusanu
nvm that, is obvious that I should lol
Remus Rusanu
The body of a 403 "should" contain the details of the error. Whether a client is prepared to make use of the information is another story. It makes the most sense for this format to be the same as the format for all other payloads (e.g., XML, JSON).
Rich Apodaca
... and if the details aren't returned in the 403, a 404 "can" be used instead (doesn't sound like the best option to me, though).
Rich Apodaca
The 404 option is for the event that a 403 might reveal details about the application that you don't want unauthorized users to know about - if a non-administrative user hits an admin-only URL, for instance, you might not want that user to know that it's a valid URL for admins, etc. In this case, though, the 403 is entirely appropriate.
Greg Campbell
Personally, an exceeded quota seems like a perfect fit for 402 Payment Required but user agent support is sketchy :-(
Hank Gay
+1  A: 

The main choice is do you want to treat the HTTP status code as part of your REST Api or not.

Both ways work, are restful, etc.

The HTTP Status code is part of your api

  1. You will need to carefully pick 4xx codes that fit your error conditions. You can include an xml message as the payload that includes a sub-code and a descriptive comment.

  2. The clients will need to use a software framework that enables them to get at the HTTP-level status code. Usually do-able, not always straight-forward.

  3. The clients will have to distinguish between HTTP status codes that indicate a communications error and your own status codes that indicate an application-level issue.

The HTTP Status code is NOT part of your api

  1. The HTTP status code will always be 200 if your app received the request and then responded (both success and error cases)

  2. ALL of your responses should include "envelope" or "header" information. Typically something like:

    envelope_ver: 1.0
    status:  # use any codes you like. Reserve a code for success. 
    msg: "ok" # A human string that reflects the code. Useful for debugging.
    data: ...  # The data of the response, if any.
  3. This method can be easier for clients since the status for the response is always in the same place (no sub-codes needed), no limits on the codes, no need to fetch the HTTP-level status-code.

Here's a post with a similar idea: http://yuiblog.com/blog/2008/10/15/datatable-260-part-one/

Main issues:

1) Be sure to include version numbers so you can later change the semantics of the api if needed.

2) Document...

Larry

Larry K
Ty. Option 2 seems like SOAP in rest clothes though...
Remus Rusanu
No, tunneling everything through a 200 is not restful at all. It prevents intermediaries from understanding the result of an operation, which will kill any form of caching, it hides the semantics of the operation, and it imposes understanding the content of the message to process an error, breaching the self-contained messages constraint.
serialseb
Returning error details with a 200 might not be RESTful, but this is a useful answer nonetheless (if you ignore the "Both ways are restful" remark)... The larger point may be that a RESTful API might not be the best option for the OP.
MB
+3  A: 

Remember there are more status codes than those defined in RFC2616, the IANA registry is at http://www.iana.org/assignments/http-status-codes. For the case you mentioned status code 507 sounds right.

Julian Reschke
A: 

There are two sorts of errors. Application errors and HTTP errors. The HTTP errors are just to let your AJAX handler know that things went fine and should not be used for anything else.

5xx Server Error

500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates (RFC 2295 )
507 Insufficient Storage (WebDAV) (RFC 4918 )
509 Bandwidth Limit Exceeded (Apache bw/limited extension)
510 Not Extended (RFC 2774 )

2xx Success

200 OK
201 Created
202 Accepted
203 Non-Authoritative Information (since HTTP/1.1)
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status (WebDAV)

However, how you design your application errors is really up to you. Stack Overflow for example sends out an object with response, data and message properties. The response I believe contains true or false to indicate if the operation was successful (usually for write operations). The data contains the payload (usually for read operations) and the message contains any additional metadata or useful messages (such as error messages when the response is false).

aleemb
+1  A: 

Don't forget the 5xx errors as well for application errors.

In this case what about 409 (Conflict)? This assumes that the user can fix the problem by deleting stored resources.

Otherwise 507 (not entirely standard) may also work. I wouldn't use 200 unless you use 200 for errors in general.

Kathy Van Stone
+3  A: 

As others have pointed, having a response entity in an error code is perfectly allowable.

Do remember that 5xx errors are server-side, aka the client cannot change anything to its request to make the request pass. If the client's quota is exceeded, that's definitly not a server error, so 5xx should be avoided.

serialseb
A: 

If the client quota is exceeded it is a server error, avoid 5xx in this instance.

fixed annuity