Recently, we’ve been having a lot of discussions here at Broadleaf Commerce about how to write good REST API documentation for our new microservices offering. It may seem like a fairly simple task, but it carries a lot of weight since an API is only as good as its documentation - if someone doesn’t know how to use a resource, they won’t use it!

I was tasked with investigating some of our options and I spent a good bit of time exploring them. Since we are a Spring-based framework, the tools I tested were all Spring-related libraries.

The initial implementation we had for our API documentation was using Spring REST Docs. This worked reasonably well, as we could simply write a test where we make each request with MockMvc, assert that the output is correct, and then leave it to the utility to output useful asciidoctor snippets for the request/response. We could then include these snippets in our general prose documentation (also written in asciidoctor), and then have the asciidoctor Maven plugin build our final HTML.

There are a few problems with this. First of all, the UI is not nearly as modern or user-friendly as many other documentation solutions. Furthermore, the documentation requires tests to be written to generate the snippets, which is not necessarily something you want your documentation to be tied to. Lastly, there’s no API console functionality, meaning the user has no way to actually directly try out some requests.

Using these pain points as motivation, we investigated a different path: the OpenAPI Specification (formerly known as the Swagger Specification). The benefits of OpenAPI are numerous. Firstly, the concerns of the content of the documentation and the UI are completely decoupled - as long as your API specification matches the OpenAPI standard, there are numerous UI libraries that you can choose from to display the content. Some of these UI libraries can interpret the specification and generate an API console for your requests, which is also a great advantage. Another big benefit is that it’s widely known and supported (https://openapi.tools/), and can be generated in a variety of ways.

I investigated the Spring Fox project, since it has magical support to scan your Spring REST controllers and automatically produce an OpenAPI spec from it. From my time with it, I was impressed with how much it automatically produced! With a relatively tiny amount of effort, I had a full OpenAPI spec generated, which I was able to display with both Swagger UI and Redoc UI with minimal effort.

I also investigated Restdocs-API-Spec , a project that Spring officially endorses. It essentially mimics the Spring REST Docs patterns, but instead of generating asciidoctor snippets, it generates custom snippets that it uses to build an OpenAPI spec.

While both Spring Fox and Restdocs-API-Spec are great projects, for a platform like ours, there are inevitably places where we need further customization and different defaults. These tools do have support for further tweaking, but come with their own added burdens such as polluting production code itself with things like annotations containing detailed prose about a particular endpoint. These are especially undesirable, since if in the future one of these projects goes out of support (which Spring Fox is nearing), suddenly we’d end up having a lot of production code that needs to be changed.

Keeping all of this in mind, we decided against leaning heavily on any particular utility to try and forcefully reshape it into being an automatic solution that solves all of our problems. We will inevitably run into limits with such a utility, and in the worst case it will hit EOL and leave us stranded. We instead elected to manually write our OpenAPI specification, rather than depend on any auto-generator.

This allows us to preserve flexibility with how we produce documentation, rather than potentially leading to a scenario where some decisions are made based on their compatibility with a particular utility. Once we establish the basic patterns and get comfortable with this process, we can evolve it over time to introduce our own helpful utilities for generating the boilerplate parts. The difference will be that everything will be personalized to our specific requirements, and we can always resolve any pain points.

While it can be argued that “doing it the hard way” is not an ideal solution, for something like API documentation, acting with intent is quite valuable. Your API documentation should be a first class citizen, and not just an afterthought.