tl;dr API documentation is about defining an interface rather than documenting an implementation. We write API documentation by hand using OpenAPI and it is working well for us.
The NRK TV team spent quite a long time finding a way to write documentation that works for us. I think there are mainly three misconceptions about documentation that held us back in finding a better way.
Misconception 1: Documentation should be generated from code.
“The only way of making sure documentation is updated is by generating it from the code. Also, documentation is a boring task and boring tasks should be automated.”
The impedance mismatch between the power of your type system and what you are trying to express with your documentation is, unless your API is trivial, most likely large. The gap between what can be auto-generated from the code and what you are trying to express must be closed somehow. Typically this is done using code annotations and configuration of the tool that generates your documentation. This can lead to a complex regime to generate documentation that in the end is quite simple to write by hand.
There are many examples in NRK TV of auto-generated documentation that has been consistently wrong for many years. It is in sync with the code, but that is not a guarantee for correctness.
On the other hand, writing this documentation by hand is pretty straight forward. Following the OpenAPI specification we can generate the documentation HTML using Swagger and Redoc. Developers that choose to write the specification using whatever tool they prefer. VS Code with a suitable set of plugins for a live preview is quite popular among developers.
One effect of auto-generated docs is that the developer does not need to be concerned about the resulting documentation. For example our documentation claimed productionYear would never be null because this was how the Swagger documentation was configured for all values. The developer does not really have to take into account what the documentation is, it is generated by itself. However, there was a check in the code that set the productionYear to null if productionYear was greater than the current year. This caused an early publication of Unge Lovende to crash on certain platforms as the clients actually believed the documentation, therefore they crashed on parsing the null. If the implementation had been driven by the specification maybe that null-check would have not been added.
Misconception 2: The backend developers should be in control of the documentation
“The backend developers write the implementation, therefore they should document the API”
This second misconception follows from the first, in that even if we agree that documentation should not be auto-generated, it should still be owned, maintained and written by the backend-developers. At NRK all source is open to all developers internally, but there is still a hurdle for many client developers in commiting code to a code-base written in .NET and requires the release of components they do not normally work at to update documentation.
If the backend developers control both the documentation and implementation it will typically lead to a situation where the backend developers also design the API. They might choose to take input on the design from others, but ultimately if they document the API they control the design of it.
If the documentation on the other hand is in a repository separate from the API and is not bound to a typical technology used mostly by backend-developers (such as .NET or the JVM) it is easier to establish a common ground for everyone. It is better to have a separate repository with simple, static hosting of OpenAPI documents that is easily accessible for all developers.
For example, our legacy search API lacked proper documentation from the original developers. Even it is defined as legacy it is the only search endpoint, so it needs to be properly documented. The search API had been documented by a backend developer who tried to reason about what the code was doing and then express the behavior using annotations. The different results, such as a series or an episode, implemented an interface IElasticHitVM that represents different types of hits. Reasoning about those implementations using reflection gets pretty hairy, so this is how far the backend developer got:
On the other hand, for exactly the same search endpoint, a web developer generated JSON Schema to describe the endpoint. The JSON Schema was being used to build a new web frontend search, so it had to be specific and correct. This ended with a much richer model that plugged straight into our documentation (OpenAPI builds on JSON Schema). There are buttons for each type of hit where one can browse the different types of results and dig deeper into the data structures. This is more helpful documentation than what was generated from the code:
To me this demonstrates that it is a better strategy to open up so that all developers own the documentation.
Misconception #3. The task at hand is documentation of the implementation
We need to document what we just built so that it is easy to use.
I used to think that API documentation was about documenting the implementation, but it is really a specification of what the API does. Therefore, it is more specification and design than documentation. I would like to quote Louis Srygley:
“Without requirements or design, programming is the art of adding bugs to an empty text file.”
When both parties – both producers and consumers of the API – share the ownership of the specification we can work together on the design. There are trade-offs that need to be made through deep understanding and collaboration, for example related to caching, resiliency design etc. Having everyone being able to take part in suggesting changes, designing new endpoints and giving feedback is a big win for API design.
Similar to how we rarely get good interface design in code by writing a class and clicking “extract interface” we need to carefully design APIs by writing the interface first.
I have often struggled – both in previous jobs and at NRK – with the API design being dominated by either the client or the server developers. This leads to APIs that are either hard to consume or difficult to build, operate and maintain. With a shared OpenAPI specification repository there is a formalized way to work with API design and better collaboration as a result. I would like to stress that this does not serve as a substitute for talking and drawing on the blackboard for design meetings, but is a way to formalize the result and suggest changes where everyone is at the same level of abstraction.
There are also promising – and for all I know useful – tools for working with Open API documents without writing everything in plain text. There is no value in writing everything by hand in itself, the value is not being bound by using one specific tool.
I also think this applies this full stack developers. In some cases we have had a web developer writing the API for new functionality. However, even if that developer is writing both the API and the web client, there are still Android, iOS, AppleTV, smart-TVs etc to take into account. It just means that the developer needs to wear a couple of hats at the same time, the issues described here are still the same.
For internal messaging systems there is an interesting AsyncAPI initiative, but I will leave that for a future post.