API Design — the basics
Some time ago I presented a talk about API Design and its basics. As it was presented to small group of people, I decided to write a post about it.
Why should I care?
First of all, your API is the front door of your company. If you expose your API externally, it should be safe, have a well designed contract and all the points that will be better explained below. Even if you don’t expose it externally, you probably have internal applications that must consume it, if things are not ok, you’re gonna run into problems.
Companies earn money with APIs charging for the requests that are made to the API. This point explains itself, with a bad design, you may need to version it more often, more chances to break, etc. If you run into problems, nobody will call it and you get no money. Bad, right?
APIs can help your system to scale, a bad design can lead your API to be unable to scale, which means that you are creating a new bottleneck. And there are a lot of other reasons why you need to care about it.
Defining how your API will be accessed is pretty important, you don’t want it to be open and free to send requests, right? It’s always good to ask yourself a couple of questions and get good answers to them.
- Is this API accessed externally of my network? Do I need to deny any external accesses?
- How authentication will work? Do I have/need a identity provider?
- What’s the process of authentication? Call a OAUTH server to get a token and then call the API?
- Do I need a API Gateway?
- Which authentication strategies make sense to my API?
- Do I want authorization? authorization and authentication are different stuff. Which levels of authorization do I need? Which profiles do I need?
- Transport must be safe, think about HTTPS.
Respect REST principles
It’s very important to respect REST principles to have a clear and concise contract. Use correct HTTP codes and status, care about the URIs, HATEOAS, contracts, etc. Take a look into some REST anti-patterns.
Discuss contract and its changes
Discussing about the contract is very important. Design it properly, only add things on the contract that you are sure.
Think about future perspective, not only with developers, but you can involve business team as well. Ok, we’re solving this problem now, but in the future, how things will look like? Do we have a perspective?
Contracts must be flexible, but not much :) Make it flexible where it makes sense to. Do not do workarounds on the contract to make it flexible. There is a slightly difference between flexibility and mess :D
Contract is not only request response, you can consider a lot of things as part of the contracts, here are some:
- HTTP methods.
- HTTP status codes.
- Sort order.
Involve more people on contract discussion, it’s always good to have more people thinking and considering things that you, maybe, wouldn’t.
Always remember this sentence:
comply with your consumers, do not surrender to them
Otherwise you’ll build a messy API and you definitely will run into problems.
Write contract tests to be sure and confident that you are delivering a consistent contract.
Not taking a decision at the same time you are thinking about a design is always good. Studies say that after a good night of sleep you take better decisions. Defer your decision for the next day, I’m sure you’ll be considering more things with a clear mind.
When we are introduced to a problem, our minds automatically start thinking about solution and many times we are so certain that the solution you thought is the best that your mind is lead to think that this solution is the one. But there are some things you can do:
- Deferring the decision, as explained above.
- List pros and cons.
- Draw the solution.
- Discuss with other team members (more or less experienced).
Contracts break! Business evolves, it’s natural and we need to accept it. Versioning is a mechanism to support different versions of the contract.
There are different strategies to support versioning, I’ll list two of them here:
- Inform version on the request URI.
- Inform version on the request headers.
Once we have a new version, we’re adding complexity to our API, meaning that supporting 2 different versions we need 2 different pieces of code, take correct decisions, tests, contracts, etc. Not a easy job, right? So, do not have many versions at the same time, we need to avoid complexity because:
many versions -> more complexity -> more bugs -> customer not happy :(
It’s important to deprecate old versions to help avoiding this over complexity. If we release version 2.0.0, we need to let our consumers know that there is a new version and version 1.x.x will be deprecated. Usually you need to give some time to the consumers to adapt to the new version, and this adaptation time shouldn’t be too long. This way, we avoid having many versions and everyone is happy :)
In the way from announcing a new version until removing it, it’s a good practice to collect metrics of which consumers are using which versions. This way you’ll be able to communicate in the middle of the way with them to remember them that the version will be discontinued.
Having a standard will make your API more consistent. Once a consumer call one or two endpoints, he will know how responses are, status codes, pagination, headers, authorization/authentication, filters, etc.
Imagine the case that you have a API which each request have different formats, options, status, etc. It’s not good for consumers, right.
Now imagine a API that is very concise, how good and easy it is to consume it? And we can even say more, imagine a company with many APIs, and all APIs follow the same standard, it’ll be super easy to consume and work with this API.
So, picking a standard is a good practice. I’ve worked with a specific standard called JSON API and really liked it. I encourage you to take a look into this.
Last but not least, how are you documenting your API?
Consumers need to clearly know how to consume your API. A good documentation MUST respond some of the questions below:
- Which are the endpoints that are available?
- Which headers are required?
- Which query parameters are available?
- Which method should I use?
- What is the HTTP response?
- How is the request body?
- Is this API call synchronous or asynchronous? If asynchronous, how do I poll it?
- Which versions are available and what are the differences?
- How long does a specific version will live?
Swagger helps, but it sucks in some aspects :) maybe the open api 3.0 specification is a bit better, but don’t be tied only to Swagger. There are other options on the market, even open sources options, doing a quick research is always a good option.
More on documentation importance here.
I just realized how long this post became. I’ll write new posts in the next weeks going deeply in each of these points written here.
I really hope I helped you to understand some things that are important to consider when designing your APIs.
Feel free to comment here if you wanna discuss more about it.