2 steps to better API Error Codes

One of the biggest difficulties developers can have when writing code that talks with an API is dealing with errors and exceptions, and translating those errors into something meaningful for their applications.

photo by Bent Jensen

Because APIs are based on different technologies and libraries, error codes are often inherited and do not make sense to whatever framework the consumer is using. Even worse is when those error codes and messages are simply passed through to the end-user without any manipulation by the application.

So, how can you make sure that all your API consumer understand your error codes and can handle them properly? If you’re offering a REST API, consumers expect your endpoints to behave like any other HTTP endpoint, so a good start is to simply follow the standards.

Whenever possible use common HTTP status codes

HTTP status codes have been created for a reason. RFC 2616 was published in 1999 and defines the HTTP/1.1 protocol, which is the one being used by most of the Web now. It also describes a set of status codes that Web servers should use as replies to callers.

Among some other status codes, the protocol defines two main classes of error codes:

  • codes starting with 4 (e.g. 400, 401, 412) are considered Client Errors: the caller is doing something wrong and the payload should present a possible solution to the problem;
  • codes starting with 5 (e.g. 500, 503, 504) are considered Server Errors: there’s something wrong with the way the server is handling the call and the payload should give more details about the situation, including if it’s permanent or temporary.

In both cases, the protocol definition explicitly says that servers “SHOULD include an entity containing an explanation of the error situation”, so it’s a good practice to do it.

When not possible, use HTTP 400 or 500

While common HTTP status codes can describe most situation where an error occurs, there are some cases where a specific API error cannot be handled in this way. In those cases you’ll take advantage of throwing error details in the payload and just use the generic HTTP 400 or 500 error codes.

The payload format can change according to what MIME types your API uses: you might reply with a JSON payload including your specific error code and an optional error message, or with an XML body with similar information.

Bonus: don’t use generic HTTP 404 for missing API methods

Calls to non-existent API endpoints that correspond to missing methods shouldn’t be handled by your generic Web server handler. In some situations, letting the Web server reply with a 404 will send the generic “Not Found” HTML page back to the caller which doesn’t make sense if there’s not a human on the other side of the line.

Instead, either reply with a 404 but using a body that your caller can understand (JSON or whatever MIME type you’re accepting) or, even better, reply with a 501 (Not Implemented) if the method is not implemented. According to the HTTP definition this is “the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource”.

UPDATE [thanks to comments by Derrick and Jonathan Rochkind]: if the method is implemented but not available for a specific resource, you should reply with a 405 (Method Not Allowed), indicating that the request method is not allowed for the requested resource.

Conclusion

Make sure your API is replying with the right error codes in a way that makes sense to callers. By using well-defined standards you’re making life easier for developers and also opening your API to better interoperability.

13 thoughts on “2 steps to better API Error Codes

  1. Corneliu I. Tusnea

    Bruno,

    We also found quite important for APIs not to return 404 if an actual entity is missing.
    It feels obvious that you should return 404 however deployment issues or DNS issues can take your API offline for few minutes and a call will get back a 404 making it impossible to know if the actual entity has vanished (and should be marked as deleted) or the API is simply broken.

    Regards,
    Corneliu.

    Reply
    1. Bruno Pedro Post author

      The correct response for that situation should be a 503, indicating that the server is down for maintenance and unable to fulfill the request from the caller.

      Reply
  2. Derrick

    501 is only appropriate when your app doesn’t support the method for *any* resource, as indicated in your quote from the RFC (e.g. you don’t support PUT). If a particular *resource* can’t handle the method, you should use 405 Method Not Allowed (e.g. if someone POSTs to a GET-only endpoint).

    Reply
  3. Pingback: 2 steps to better API Error Codes | Bazaar | Scoop.it

  4. Jonathan Rochkind

    I _do_ agree with the general thrust of the article. I write lots of client code for lots of different HTTP apis (written by various vendors and other organizations which are not mine), and proper use of standard HTTP response codes is _super super helpful_ to me as a client writer. I agree wholeheartedly.

    But I think you possibly make or promulgate a misunderstanding of 501 here.

    > Instead, either reply with a 404 but using a body that your caller can understand (JSON or whatever MIME type you’re accepting) or, even better, reply with a 501 (Not Implemented). According to the HTTP definition this “the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource”.

    In the HTTP spec, “method”, means an _http method_, like GET, POST, (the new proposed) PATCH, etc. And even the quote says “not capable of supporting it for _any resource_”.

    Ie, if your app does not support PATCH _at all_, then, sure, returning 501 is the right thing to do.

    If your server doesn’t support POST to this specific URL? Nope, not 501. Let alone if your not-entirely-REST API supports /api?command=send but not /api?command=selfdestruct — definitely not 501.

    I am not sure if you intended it this way, but a casual reading of this post could give you the wrong idea about 501, it is suitable for use only in very specific circumstances, most ‘the api call you made is not understood’ errors really are going to be 404s (but, sure, with an appropriate json/xml/whatever with machine readable details, that’s be great).

    Reply
    1. Bruno Pedro Post author

      I agree and I updated the post with information about using a 405 (Method Not Allowed) for situations where the method is available but not for the resource being requested.

      Reply
  5. Paddy Foran

    Maybe it’s just a crazy personal preference, but I’ve found that whenever my error codes do not point to a single, machine-discernable resolution, I’m signing up for a world of hurt in writing a user-friendly client.

    My approach has been to combine semantic HTTP status codes with fine-grained, specific application error codes. The status codes give a general idea as to what went wrong, while the application error codes (represented as a code/field pair) point to what went wrong and the specific JSON field that needs to be corrected. This has made it really easy to write clients that tell the user a lot more than “your request is bad and you should feel bad.”

    Reply
  6. Pingback: 2 steps to better API Error Codes | Atopicabout...

  7. Pingback: Pivotal Tracker launches new API in public beta

Leave a Reply