We have all seen the numerous articles and tutorials related to great REST API design on the web. They usually talk about proper coding techniques and how to expose the endpoints in some given language. While useful, and definitely needed, they often miss some of the fundamental high level ideas that make great APIs work. In this article we will cover 8 tips which I have learned consuming and providing APIs in the enterprise in the hopes you can implement them in your next project.
The task here is to make an API that is ridiculously predictable. To do this write out all the endpoints you intend to make and any parameters they will take. Now make sure the naming is consistent, that the parameters are in the same order and that they have all the needed operations. Do you have products, orders and customers? They probably all need some form of ID and name. Don’t make one endpoint take an only ID, have another take name only and then one with both. Don’t have an endpoint that is /product/ID and another /ID/customer. As a consumer of APIs I expect to access one resource in the exact same way I access another.
Another trick for consistency is to make sure you take a look at parameter types. If one endpoint takes an ID as an integer, don’t make another take an ID as a form of string. As a user I don’t want to have to guess the type of parameters for each and every endpoint.
Besides how you access data in your API, you should also think long and hard about the responses given by your API and their uniformity. This is currently a big problem with a recent API I am using. Developing against one endpoint, I was surprised to discover that while every element of the results (which are in XML format… I will talk about why we might want to avoid this later) contained an certain attribute. Some had the attribute and some did not. I would rather see an empty attribute specified than not showing the attribute at all. The reason this is a problem is because if I am looping through elements, looking for an attribute, I expect to at least find it, even if it doesn’t contain a value. This is like looking through a series of database rows only to find out that some of the rows are missing a column that others have. Then it starts making you doubt all results and asking the question “Are any of these other attributes possibly going to disappear on me?”
Have you ever talked to someone on the phone and asked them to do something for you only for them to just reply with a simple “OK”? Then you pause and have to ask “Did you actually do it?” Great APIs do what you ask but also reply with some additional information about what they did. If your API will create a product, have it reply back some information about the newly created product. Don’t force the client to have to send you another request to ask information about what it just asked you to do. This may seem like a no brainer to some of you, but you would be surprised how many APIs just do something and send back as little as a 200 OK response. It is OK for your API to have a little chattiness to it as long as it provides the client some very useful and obviously needed information about what was done.
What would you rather do: ask someone to pick up your dry cleaning or tell someone to get in the car, drive to the dry cleaning place, get out of the car, open the door, walk inside, ask the clerk about the garments, exit the store, get in the car and drive to where you are? Don’t make your clients have to call multiple endpoints just to do a common and otherwise atomic task! You can fight this by providing defaults for parameters and allowing the client to override whatever values they need to for customizing the request.
One API I am currently working with does it the long way and it is painful and time consuming. What should be a single request to create a subscription product, and clock in at 300-500 ms, is instead forcing me to make 7 calls each being 300-500ms round trip. This makes a process that should be 300-500ms into several seconds! Times like these add up and it is being noticed by the customers of our products which uses this API.
This tip is a straight forward one. If it succeeds, return a success status code like 200 OK. If it fails, issue the appropriate status code to show the failure like 404 or 500 or whatever. What we want to achieve here is that the client using the API can look at the response code first before looking at the body of the response to know what to do. One API I have worked with will actually return a 200 OK status code but then show an error in the content type. So even thought I get a success, I have to always check it to see if in fact it was really a success. Don’t do this. Just return the proper status codes to begin with and all will be smooth sailing.
Great APIs always do what they can to serve great data on demand and as quickly as possible. Part of this is not to do tasks that you already know the answer to because you just served the answer to someone else who had the same questions. In other words, use techniques like server-side caching wherever possible. If a user asks for information on product 1 and then another person asks for information on product 1 (and they are the same exact request) a few seconds later serve them the data you gave the first request. Don’t look it up again just to give them the same data you looked up and served just moments earlier. Just be sure to also put an expiry date on that cached copy so it doesn’t get stale.
One service that does this well is Chargify. I can ask about a given subscription product and they will reply in roughly 200ms. Which is pretty fast. But if I ask about the subscription a minute later it will serve me that same data in 97ms. Understand that not all endpoints and lookups can be done like this, but if you have data that doesn’t change, or changes very slowly, think about using a cache in your API to speed up requests. Your clients will love you for it. If clients mix it with their own client-side caching they will be humming along happy and content.
You have many methods for securing your API: basic auth, digest auth, oauth, no auth etc. When considering which method to use, always take into account things like speed and ease of use (tips 3 and 5 above). If you implement SSL, I suggest going with Basic Auth as your method of choice since it is pretty easy to implement and enjoys a bit of a performance bump due to only needing one request rather than two (digest auth typically requires at least 2 requests to authenticate). Now obviously if you are not using SSL, go with methods that are secure like digest auth or oauth or one of the other methods out there.
Congrats! Your API is a success and tons of people are out there using it. But now they have come to rely on it for a ton of products and projects. But you want to make updates without breaking things for them. If you version your API you can keep things separate. I suggest using versioning as a parameter or part of your endpoint naming. Things like GET /v1/product/id or GET /v2/product/id or GET /product/id?v=1. You could also choose to implement this through headers, but whatever method you choose be sure to stick with it across all versions.
By versioning your API you can keep customers using the version that works for them and choosing when is best for them to move to the new version. You can also consider when to deprecate it and turn it off without needing to do anything about your current versions.
Number 8 is a personal preference tip. Having dealt with many APIs over my career, both JSON and XML, I can tell you that I have always found JSON to be the easier of the two. It is often less verbose (leading to less to transmit), easier to represent complex objects (precise) and works universally well with other services (just about everyone is using JSON these days). XML tends to be very verbose and not often easy to represent complex items and needing something like a DTD just to validate it. I would start with JSON and if you want to later implement XML then knock yourself out. However, I think once you start with JSON the drawbacks of XML will become very apparent.
We covered 8 tips that can help you think better about your next API design. APIs are changing the ways we deal with integrating systems and their quality is becoming paramount. If you think about your end users when designing your endpoints, and how you can make it easier for them to use, the more successful your API will become. If a client can use someone else’s API to do what your API was designed to do, but easier and faster, they are going to use theirs.
Don’t make the critical mistakes of being inconsistent, using responses unwisely, being quiet about what happened (not being chatty) and being slow. It is going to doom your API and if your API is your business, it will take your business down with it. Thank you for reading! 🙂