We all know that using a well-designed API is extremely rewarding, while using a poorly-designed API can be frustrating enough for us to give up altogether. However, when we ourselves strive to build the best-designed APIs possible, we tend to trip up right away, wondering: what makes an API’s design good or bad?
For Arnaud Lauret, creator of the API Stylebook and author of The Design of Everyday APIs, APIs and everyday objects share a lot in common when it comes to their design. He told us more about these similarities and his other principles of good API design at our Platform Summit, giving us plenty of humorous examples along the way! Today, we’ll share those same principles with you.
Arnaud’s Three Principles
Good design can be broken up into three main aspects, says Arnaud, and those are purpose, usability, and constraints. If you bear each principle in mind when building an API — or any household object for that matter — you’ll come away with a fantastic result.
Let’s dive into each of these design principles, looking at how they work and how we can optimize them.
“Behold, the Kitchen Radar, a new device for heating food that uses military grade technology to reduce your cake-baking time from forty minutes to eight! Simply mix your wet ingredients, heat for a few minutes, add the dry ingredients, and heat for a few more. You can even defrost food in the kitchen radar, but you’ll have to press the interface’s single button intermittently (leaving the device on for seven seconds and off for an equal time) to do so.”
Arnaud’s humorous analogy is, of course, poking fun at a hypothetical microwave with a single off-on button — which would clearly be a poor design choice. A single button interface exposes the inner-workings of the device (which is only capable of heating food intermittently), and doesn’t bear any concern for the ultimate purpose of the product.
Pit that against a regulator microwave oven, where you can
heat food at <power> for <time>, and you’ll see that good design pays attention to the purpose of the product and minimizes any of the internal constraints that could get in the way of that purpose.
The result is for the same implementation of heating food, you’d need 20 lines of code to use the Kitchen Radar (consisting of a big loop that switches the device on and off at intervals proportional to the power), but just one to use the microwave.
The lesson for API practitioners here is to bake purpose into the design. Understand the end developer needs, structure your service with enough methods for the majority of required calls, and make all parameters discoverable and clearly defined within API documentation.
“An API is first and foremost an interface for people”
Once the purpose of your API is out of the way, usability is the next design criteria to consider. Arnaud says that usability itself can be broken down into three categories: representations, interactions, and flows. All of these together ultimately contribute to predictable design.
Usability in Representations
All of the representations in your API need to be intuitive, which is to say that all users should be able to understand all names and other such details at first sight.
Imagine an alarm clock shows you a countdown of the seconds until it rings — not a very useful or usable representation. Compare that to an alarm clock that shows you the exact time at which it will ring — that’s now a relevant piece of information for the user.
To emulate this idea in your API’s design, make sure that representations (especially names) are as consistent, straightforward, and relevant as possible. If your users need access to customer IDs, then call them exactly that —
customer_ids — and don’t go using other names for the same thing.
Usability in Interactions
Next up on the topic of usability: Make interactions with your API as usable as possible. Of course, there’s a metaphor for that too.
With some washing machines, you can choose the temperature, the speed, the load size, and more. With others, you simply choose a program and the machine takes care of the rest. For something as mundane as washing a pair of jeans, which would you rather have?
This usability in the interactions you make with a product is all about having few, straightforward inputs (and letting the code extrapolate any other parameters). Just as important is providing valuable feedback throughout the process.
Much like a washing machine may tell you the “DOOR ISN’T CLOSED” instead of just refusing to run, an API that returns valuable error feedback is leagues ahead of an API that refuses to work and offers no reason why.
Lastly, don’t forget about positive feedback: it’s helpful to know your washing cycle has started and you’ll have your jeans ready in 40 minutes, and developers’ jeans matter too.
“Design straight-forward API interactions. Only request minimal and straightforward inputs. Avoid requesting thousands of parameters…”
Usability in Flows
Finally, there’s the usability of flows. A usable API flow makes processes as smooth as possible, so that users can get to the desired result faster and easier.
Consider an elevator with just one button outside and no displays. To get from one floor to another, you have to call the elevator, choose your floor when inside, ride it to wherever it’s headed, and then ride it to your floor.
By simply adding an UP or DOWN symbol to the elevator, users can take the elevator headed in their direction. You can go a step further an introduce two buttons outside the elevator, allowing users to choose which direction they are headed from the get go.
In API design, this means improving feedback, minimizing errors, and aggregating actions. All of these things get you to your desired result faster and easier.
Good Design is Predictable
The endgame for API usability is a predictable API; if users know what to expect from your API, they’re a lot less likely to struggle using it. You can break predictable design up into three elements:
- Consistent: Build an API which is consistent with itself, across the organization, and with global standards and practices. This makes interacting with your API effortless.
- Adaptable: Allow users to adapt your API in a way that suits them best. Offer pagination, sort, and filter functions let users choose their representations (content negotiation), and internationalize everything from languages to currencies… just don’t make it too complicated!
- Discoverable: Help users find the functionality they need and learn the API’s design from the inside-out. This includes metadata for pagination and maximal usage of underlying protocols, such as using Approve to denote acceptable HTTP methods.
Last of all, for effective API design, impose constraints if they allow you to improve your product. Just like a diving watch will make sacrifices to its design to make it more suited for diving, you should willingly constrain your API if that allows you to better tailor it to the end purpose.
If latency is an issue, build coarser grain APIs that don’t need to be called as much. Similarly, you can rate limit the frequency of API calls or offer webhooks that give users updates only when necessary.
Here, it’s not just the user that matters. If you can make reasonable design compromises to improve delivery of the product from your end, like limiting API calls to improve scalability or offering asynchronous returns to improve performance, that’s worth considering.
“Focusing on usability is a very good thing. But, it must not be done without forgetting that design must be constrained.”
Empathy and Context
Good API design is just like good product design. Two things matter above all else: empathy and context.
Empathy represents an understanding of the user’s needs and constraints and would focus on nailing down the purpose of your API or improving usability, while context represents an understanding of how the product is poised to deliver a certain benefit, which would include everything — purpose, usability, and constraints.