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.

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.