Editor's note: We've got an updated eBook on the topics covered in this blog series: Web API Design: The Missing Link.
In the previous posts in this series about Pragmatic REST API design, I talked about simplyfing associations, using the HTTP ? to hide complexities and optional parameters, choosing plural nouns and concrete names, and more. Check out the full series.
What about errors in the context of RESTful API best practices? Many software developers, including myself, don't always like to think about exceptions and error handling but it is a very important piece of the puzzle for any software developer, and especially for API designers.
Why is good error design especially important for API designers?
Bottom line, it's about making your APIs intuitive and making developers successful.
First, developers learn to write code through errors. The "test-first" concepts of the extreme programming model and the more recent "test driven development" models represent a body of best practices that have evolved because this is such an important and natural way for developers to work.
From the perspective of the developer consuming your Web API, everything at the other side of that interface is a black box. Errors therefore become a key tool providing context and visibility into how to use an API.
Secondly, in addition to when they're developing their applications, developers depend on well-designed errors at the critical times when they are troubleshooting and resolving issues after the applications they've built using your APIs are in the hands of their users.
How to think about errors in a pragmatic way with REST?
Let's take a look at how three top APIs approach it.
No matter what happens on a Facebook request, you get back the 200 status code - everything is OK. Many error messages also push down into the HTTP response. Here they also throw an #803 error but with no information about what #803 is or how to react to it.
Twilio does a great job aligning errors with HTTP status codes. Like Facebook, they provide a more granular error message but with a link that takes you to the documentation. Community commenting and discussion on the documentation helps to build a body of information and adds context for developers experiencing these errors.
Provides error codes but with no additional value in the payload.
A couple of best practices
Use HTTP status codes
Use HTTP status codes and try to map them cleanly to relevant standard-based codes.
There are over 70 HTTP status codes. However, most developers don't have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to wikipedia to figure out what you're trying to tell them.
Therefore, most API providers use a small subset. For example, the Google GData API uses only 10 status codes, Netflix uses 9, and Digg, only 8.
How many status codes should you use for your API?
When you boil it down, there are really only 3 outcomes in the interaction between an app and an API:
- Everything worked
- The application did something wrong
- The API did something wrong
Start by using the following 3 codes. If you need more, add them. But you shouldn't go beyond 8.
- 200 - OK
- 404 - Not Found
- 500 - Internal Server Error
If you're not comfortable reducing all your error conditions to these 3, try picking among these additional 5:
- 201 - Created
- 304 - Not Modified
- 400 - Bad Request
- 401 - Unauthorized
- 403 - Forbidden
(Check out this good Wikipedia entry for all HTTP Status codes.)
It is important that the code that is returned can be consumed and acted upon by the application's business logic - for example, in an if-then-else, or a case statement.
Make messages returned in the payload as verbose as possible
Use plain language descriptions.
Add as many hints as your API team can think of about what's causing an error.
I highly recommend you add a link in your description to more information, like Twilio does.
Next time - versioning your API.
Please join the API Craft conversation on Google groups.