Designing bad APIs is easy. Good APIs are art.
For the past several years it feels like this hype of good UX vs bad UX is getting more and more traction, which, honestly, is good a thing, because both product stakeholders and end users are getting more aware of how important the UX umbrella actually is and how it can make or break a product.
But this is an article about API design, so why would we talk about UX? Bear with me. These days, every new project starts with wireframes, mockups and probably an interactive design. These mockups are built around the customer needs, following well established design principles to create user journeys that ensure the best experience.
On the other end of the product development spectrum, the API is, very often, treated as an afterthought. Usually, there’s a concept of what functionality it needs to offer, but throughout it’s lifetime, it ends up in patches, with different versions (without backwards compatibilities) and no consistency whatsoever.
If your in a hurry and don’t have time ‘till the end of this article, here’s how your API should be: Consistent, Intuitive, Fast, Simple to use, Well documented.
If you have a bit of time, let’s dive in…
The acronym API stands for Application Programming Interface…emphasize on Interface.
Moreover, the word “Programming” indicates that it’s being used by programmers, developers, human beings. Basically, it’s a user interface, so it’s best to treat it like we treat UIs. Who doesn’t love beautiful, well designed UIs? Those delightful user interfaces you see scrolling Dribbble and Behance.
Same goes here. Your API must offer a delightful experience for users consuming it. Although, the “end users” are other applications, the first users to consume your API are the developers that integrate said applications and just like UIs, they can feel if it’s a great API design or not.
Some say a good API design is an art.
So, how can we build a well designed API that offers a delightful experience for our users?
Well there are some aspects that should guide the design of an API at its core.
For sure, one important aspect of a good API (if not the most important one) is consistency across endpoints, its structure, the request & response formats and everything that goes into consuming it. Ensuring such a consistency, your API will basically guide the users (developers) on how to use it, without reading too much of the documentation. They can simply follow their gut on how things should work, in the same manner as you find your way very easy around a very well designed UI.
Having a consistent structure in your requests, responses and endpoints, the developer can know exactly what to expect even if there are new resources added. It will give a predictable feeling around the resource URIs. Another effect of consistency is ensuring backward compatibility between the versions of your API.
Because everything must run fast these days, speed is a decisive factor even for the simplest APIs. It’s worth mentioning that any response time over 1 second is a deal breaker for the majority of users.
With that in mind, performance is something you want to think of early on, but try to avoid over optimizing everything. This can slow down your development time without any good reason for your business.
The API is part of your MVP (or in some cases, is the MVP), so like any Minimum Viable Product — build, measure, learn, repeat.
It’s very easy to go overboard with implementation and before you know it, you’ve added 3 or 4 extra layers to your API without any business need at this point.
Good UIs are intuitive and simple to use, you often get around with just a few clicks. Your API should be the same — simple as possible.
Try sticking to the basics, but do them well. It should be so simple to use that it’s basically impossible to mess up a call.
If you can reduce a transaction in your business flow to one call instead of two, it goes without saying that you should do it. Of course, this is not always the case and simplicity may be harder to achieve in some scenarios. As long as your API helps the users achieve their goals in the best way possible.
This is probably the least fun part, but equally important. Even with a great level of consistency and KISS (keeping it simple and straightforward) around your API, you must provide accurate and useful documentation for it.
While every developer loves reading good documentation, the majority hates writing it. In most cases, it’s a separate process happening at the end of the development cycle, often caused by prioritizations. But good documentation takes time.
By integrating the whole documentation writing from day one in to your development process, you eventually form a habit out of it and it will help you in the long run.
Try to have it part of your workflow, in your commits, in your comments in the code. To make the process even faster, you can use code documentation tools that generate documentation from the source code comments. These additions won’t replace a full documentation, but for sure it will make life easier for many involved, developers, users, teams. An example of such automated tools are jsdoc, apidoc which supports several programming languages and Swagger. The later is not only a software documentation tool, but it also has an entire suite of tools for API design and development, which could be covered in an article of its own in the future.
The REST of it
When designing an API, these concepts can be applied and used no matter the architectural and technology choice.
The good ol’ REST standard is still widely used and it will continue to be, despite the new API architectural kids on the block , like Google’s gRPC (2016) and Facebook’s GraphQl (publicly released in 2015). But we’ll leave gRPC and GraphQl for another time and remember how REST works, as an API starting point.
REST APIs are based on resources that are usually entities (e.g. animals), which can have sub entities (e.g. cats and dogs) and should always be represented by nouns.
On the other hand, HTTP has verbs that are actually considered actions: GET, POST, PUT/PATCH, DELETE → the CRUD paradigm.
Therefore, building a simple REST endpoint, for example to retrieve all animals, is simply a GET call to /animals.
Moreover, REST endpoints are always a combination of HTTP verb + URI (e.g. GET /animals/dogs)
These best practices are at a google search away, but here are just a few to remember:
- Make use of HTTP verbs (GET, POST, PUT/PATCH, DELETE). Match the CRUD paradigm to these verbs, meaning POST — Create, GET — Read, PUT/PATCH — Update and DELETE — Delete.
- Don’t include verbs in URIs. For example, use GET /dogs, rather than GET /getDogs.
- Use plural nouns instead of singular. You’re consuming the resource from a collection. For example, GET /dogs would return you the entire list of dogs, whereas GET /dogs/1234 will return you that specific dog. It makes no sense to have another endpoint /dog/1234 to retrieve the same information. Same goes for POST /dogs, which means you’re adding to that collection. Don’t create a redundant endpoint like /dogs/createDog.
- Use HTTP status codes wisely: 1xx for providing information, 2xx for success messages, 3xx for redirections, 4xx for client errors and 5xx for server errors. Never use 200 OK in case of errors.
- Use query parameters for filtering and searching. For example to search for all german shepherds in a descending order, you would make a call toGET /animals/dogs?type=german-shepherd&sort=-created_at
- In case of errors (4xx, 5xx), return error details in responses
- Always provide Content-Type header
- Don’t forget about CSRF protection
No matter the technology choice, keep these things in mind for your API:
Keep it consistent
Make it intuitive
Make it fast
Keep it simple and straightforward
Provide accurate and useful documentation
Building good APIs is hard. But that shouldn’t be an excuse. Remember the feeling you had the last time you interacted with a poorly-crafted product? Your API is a product that goes out in the world, serving its users in the best way possible. Do your best and design it well.