I write this article using Google Docs. I can select a phrase, press Ctrl+K to convert it to a link, and get suggestions of possible links on the web that match that phrase. I can interact with this document from other software: attach it in an email, link to it from Trello or Slack, or edit it from LibreOffice. My colleagues can collaborate on it with me if they have access to it. These powerful integrations would be impossible without the APIs provided by these services.
Software systems are composed of interconnected subsystems. Each subsystem provides functionality that it is best suited for. Even within a single platform there can be several subsystems working together to provide a complete solution, as is common in microservice architectures.
Software developers building applications that connect in this way rely on the documentation of each service’s API to know how to use it. It is safe to say that every software developer can appreciate the usefulness of good documentation. We too appreciate good documentation; here’s how we document RESTful APIs.
Why documentation matters
My colleague Mark Boleigha once worked on a project where he had to consume an HTTP API from an iOS application. Every morning he received some YAML blob of OpenAPI documentation via email. He would then diff it against the previous copy to know what changed. I’d watch the shadow cross his face as he resigned himself to the inevitable shot of sadness each time he had to do that. We had good laughs about it; all programmers have good laughs about their misfortunes, as a coping mechanism, right?
Poor documentation stresses whoever consumes it. If the information sought is hard to find; or the documentation is incorrect, inconsistent, or out-of-date; then we will trust it less. We will seek the information we want elsewhere, probably by asking a colleague who may have worked with that system before. If priority is not given to improving the documentation, it’ll keep drifting further from usefulness until it has to be redone with much more effort. All these inefficiencies waste resources that would have been better used elsewhere.
Working with a poorly documented system is unpleasant. We once abandoned an effort to provide a Sign in with Apple option for users of an application we were building, because Apple’s documentation was unhelpful.
Documentation provides feedback on the quality of a system’s design (more on this later).
What we mean by RESTful API
Representational State Transfer (REST) is as popular as it is controversial among software developers. What exactly is a RESTful API? We won’t bother ourselves with a proper answer to that question here. For the purpose of this article, we are concerned with HTTP APIs that adhere (to some reasonable extent) to the REST architectural constraints. Most of the tips we’ll offer apply to documentation in general, but we make this clarification because some of the guidelines depend on some properties of REST. For example, we leverage resource orientation and the uniform interface to simplify documentation.
Objectives for API documentation
We want every part of our documentation to speak as one. Different parts of documentation must not conflict on the same topic. Also, the documentation must be in sync with the API at all times. We know the pain of using APIs that work differently from their documentation.
Easy to consume
The format we provide documentation in must be easy to consume by the widest target audience. Consumers should not have to be restricted unnecessarily in accessing documentation. Formats that are both human-readable and machine-readable are easier to consume.
Single source of truth
What’s the point of having documentation if its consumers need to check with another source to know that they’re consuming correct information? If the documentation disagrees with another source, the documentation is given priority and updated if necessary.
You’ve probably had to leave a piece of “official documentation” in favour of some YouTube video or StackOverflow comment because the documentation was difficult to understand. We want just the right amount of documentation without additional complexity.
As an API changes over time, we want to keep its documentation up-to-date, or even improve it, with minimal effort.
Guidelines for RESTful API documentation
Leverage HTTP’s semantics
HTTP as an application protocol was designed for RESTful APIs. Its semantics provide a powerful mental model for RESTful API design. We take advantage of these semantics to simplify our API design. For example, the GET HTTP method already tells us the following about any operation that uses it:
- it must be idempotent;
- its response is cacheable;
- it returns a collection if its URL ends in a forward slash (/).
Because these are already implied, we do not have to document them. Whenever possible, use the HTTP semantics to express properties of your API. By doing so, you will gain the established vocabulary and the possibility of seamless integration with tools that already respect those semantics. This furthers our objectives too: our APIs stay consistent (the semantics don’t change), simple, and maintainable (we don’t pay maintenance cost on HTTP).
Stay within the API’s authority
An API’s documentation should not talk about things that it’s not the authority on. Say we want to explain how to test our API using Postman: we need to explain how our clients can obtain API keys for testing, but we need not explain how to install Postman. Straying out of the API’s authority duplicates information that is best documented elsewhere. Duplicated information must be maintained to stay consistent with other sources. All that work is against our objectives, so we avoid it.
Prefer open formats
Open formats such as OpenAPI give us a common language for documenting APIs. There are many tools that make it easier for others to consume our API documentation in these formats. OpenAPI is machine readable and human readable. This makes it easy for us to maintain documentation in this format (we just edit it in a text editor), and we can take advantage of all the tools that generate documentation consoles, API client and server stubs, etc. If I give you a URL to an OpenAPI document, you can view the documentation using any client you wish: Postman, SwaggerUI, or even your custom tool. You’re empowered to use it as you see fit. You can generate a client SDK for your application, or even generate a mock server to test against.
Separate the API contract from the implementation codebase
The mention of OpenAPI may have irked you a little. Nobody enjoys writing YAML, and JSON isn’t much better. It’s sad that OpenAPI chose those formats. It’s also a chore to maintain documentation separate from code (isn’t code its own best documentation?) There are tools that try to provide a bandage over this by generating API documentation from your codebase. Their efforts are appreciated, but some due diligence is necessary when using them. Try to keep your API DTOs separate from the rest of your application, and translate from your domain models to your API DTOs. Coupling these will cause you pain in evolving your domain models; we’ve been there, it’s not funny. We eventually gave up on that approach and now prefer writing the YAML files. After rewriting a recent project from Node.js to Go, we appreciate not having to migrate the API documentation too. It’s all tradeoffs, isn’t it?
Practise contract-first API design
Still on the chore of maintaining a separate YAML file for your API documentation. There’s a minimum amount of work you have to do to maintain your documentation. If we could auto-generate everything, we wouldn’t be writing software (the capitalist dream of “human zero”). We found that the drudgery came from having to revisit our work to update the documentation, just as it’s boring to write tests after-the-fact. It’s not that maintaining API documentation is a chore, it’s that we’re doing it wrong. Now we write the documentation first and agree on it before we move on to implementation. And because it’s written in YAML rather than yet another programming language (YAPL), we can all collaborate on it. My colleagues can give me feedback on the API specification before I implement it. They can propose changes themselves. The documentation process becomes part of our software development process rather than something we do as an afterthought.
In true Agile™ fashion, we pay attention to software design before and during development. Documentation is involved in that iterative process, even up to the delivery phase. We generate the API documentation console from the OpenAPI document we write. When an API change is promoted into staging, its documentation goes with it. One way to do this is to serve the OpenAPI document at a URL on the API, versioned with the application code.
Tools we use
Everyone uses their favourite editor for writing OpenAPI documents, whether it’s VS Code with an extension or the Swagger Editor. We usually use SwaggerUI for viewing the documentation in the browser, but recently I tried RapiDoc and I prefer it. Of course, being a machine-readable format. There are several other tools that provide specific functionality you may want; see OpenAPI.Tools for a dazzling list of tools you can use. Pick whatever improves your workflow.
There are improvements we can make to our own workflow. One that has been on my mind is a tool that can streamline testing and verifying the API contract, including checking that responses conform to the documented schema. There are tools that do this, but I’ve not been able to design a workflow around them. The possibilities for improvement are open, and we’re open to improvements.
Documenting your API is important to its consumers. Your API documentation should be consistent with itself and the API. It should be easy to consume using a variety of tools. For its area of concern, your API documentation should be authoritative. Keep it simple and maintainable. If you respect HTTP’s semantics, you’ll reduce the amount of work you have to do to make a good documentation. Avoid duplicating information that’s not related to the API’s central concern. Write your documentation in an open format, preferably one that’s both human readable and machine readable. Keep the API specification separate from its implementation, even if you’re using code generation. This will prevent you from creating a maintenance nightmare in your application. Make documentation part of your software development process rather than an afterthought. Take advantage of all the software development practices you can, including version control and continuous delivery. If documentation sucks, let’s improve it.