So far, in this series, we’ve covered the basics of RESTful URL design and crafting responses from your API endpoints. In Part II, we briefly mentioned what to do in case of errors that might arise from your APIs, but in this post we take a deeper dive into what to do when it all goes terribly wrong.
If you want to brush up on the topics we covered in the previous posts, check them out here:
- RESTful API Design Part I: POST /EFF/YOU/THIS/IS/THE/RIGHT/URL
- RESTful API Design Part II: 418: I'm a Teapot, and Other Bad API Responses
There are many ways to communicate the success or failure of an API call, but these are some of the techniques we have found to be the most intuitive here at Cloud Elements, where we integrate to a LOT of APIs.
Since this is a series on RESTful APIs, we are already assuming that our API calls are being made over HTTP(S). The great thing about using HTTP for interacting with APIs is that it has built-in status codes that can give your users some good information about the success or failure of your calls. Why not make the most of them?
But, but… Why?
In our experience, great error messages are incredibly helpful when integrating with an API. Good error codes and messages should help guide developers toward the correct way to integrate with an endpoint. Some folks read through pages and pages of documentation before starting, but others are more comfortable jumping in feet first and seeing what works. With great error handling, the latter group will be able to figure out exactly what they need to do to work with your API, much faster.
The next, and most obvious reason, is that error messages need to be relied upon from within your client’s application. In order to build a robust application, it needs to be able to gracefully handle errors as they arise. Having well-defined and descriptive error messages makes the client’s job so much easier to achieve this.
But, but… Who?
Again, there are many ways to provide meaningful errors back to the client. Here are some examples of how three different RESTful services provide error information back to the client.
In all cases, Facebook returns a 200 OK, regardless if there was an error or not. In this case, rather than knowing right away that something went wrong, the client is forced to inspect the payload and take action based on the type of data returned. There is decent messaging describing the error, but an entire category of error identification (HTTP status codes) has been left out. And what are those error codes and sub-codes? I don’t know, either.
Box has great error handling, where the return status code is mapped well with the information in the payload. It is easy to tell that something went wrong, and then find out what went wrong. You’ll notice also that it includes a request ID that can be helpful for Box support to identify the error on their side and perform any additional research.
But, but… How?
So, let’s talk a bit about some of the best practices that we believe make for a good developer and client experience.
As mentioned earlier, the HTTP protocol comes pre-packaged with lots of (over 70) status codes that can provide information about the success or failure of an API call. Some are more well-known, and know what a 404 means, and what a 200 indicates. On the other hand, how many people know what a 418 is? While that may be a bad example, the point is that most likely you’ll want to use as small a subset of status codes you can, while still providing the necessary information to the client.
For example, Box uses the following set of status codes to communicate what’s happening with their API:
I would argue that this may even be overkill for many services. It really boils down to the types of data you’ve got, how the client can interact with it, and how your server handles and serves that data.
To figure out what you’ll need for your service, I would start with a very basic set, and then add more in as needed. So, start with the following list:
400 Bad Request
500 Internal Server Error
Then, if you are doing authentication and authorization, add in:
Or, if you have resources that shouldn’t be accessed by an API in certain situations:
You get the idea. Add as many as are necessary, but in most cases you won’t need to learn and implement every single status code in the spec.
Sure, but what if…
You’ll probably also come across some edge cases, or things that don’t conform to the best practices set forth by all the “experts” on the interwebs. In those cases, try to take a common sense approach that provides as much detail as possible to the client, while still sticking to the spirit of best REST error handling practices.
For example, at Cloud Elements we have found ourselves in situations where certain API calls could be made with no binary answer of whether the call succeeded or not. For example, we have certain APIs that perform operations both at an endpoint, as well as on our servers. It is possible that an operation could have succeeded at the endpoint, but a non-critical function failed to complete on our servers. For all intents and purposes, the API call succeeded, since the critical part of the operation succeeded. In that case, we return a 200 OK to indicate that the call succeeded, but we also include a header value of Elements-Error that indicates there may have been an error in some other aspect of the call. We felt this was a good way of retaining a sane RESTful structure, while still providing necessary error information to the client.
Tell it like it is
In order to make your error messages super useful, be as descriptive as you can about what the error is, and how it can be resolved. Consider including links to documentation that may be helpful to resolve an error that may be non-obvious to the user based on the status code and message. Add as much information as you can think of to make is as easy as possible to integrate with your API.
Document the crap out of the error handling strategy you’ve decided on. It is true that some will not check the docs because your API error messages are so amazing, but to get the full picture of what a client can expect from your API, they’re going to need it to all be laid out in one place.
Thanks for reading, get some REST, and we’ll see you next time.