Let’s imagine a pretty typical application workflow for a developer.
You start out a project with enthusiasm and have ideas on how to document everything thoroughly. You are confident your project will have tests, continuous integration, continuous deployment and beautiful documentation. Everything starts out as planned. The stakeholders are happy, and you’re happy too.
Then it happens. The stakeholders decide to pivot on something and want you to make the changes. You update the code, but you forget to route the documentation for that segment because it’s added in an entirely different place.
Therein lies the problem, and it’s a problem we really shouldn’t have to think about anymore. Our code changes should be directly reflected in our documentation.
At Rocket, we decided to address this problem by building a library to automatically create documentation by utilizing the validation middleware already used on our projects. The main goal was to make sure that every update a developer does in any part of the validation is immediately updated in the documentation.
The library is not published, and is only used on our internal projects where improvements are being made as needed.
For our purposes, we currently support automatic generation of:
- Route paths with methods
- Request validation
- Error validation
- Response validation
There are still “manual” parts where developers can add detailed descriptions for routes, overview of the API, specific server urls, etc. This manual part is added as yaml into the “base.yaml” file.
How does it work?
All API routes should have validation middleware to make sure routes are protected. If you’re not validating your routes then it might be a good time to start. We use koa.js and koa-router for our APIs. In the example below we have a validation middleware associated to validate the body for this route. If the validation succeeds then we move on to the actual business logic.
How are we extracting the body for our automatic documentation? In order to answer this we need to look into our validation middleware.
As you can see we are using closure here to create our validation middleware for specific request sections (body, query, header, param). The crucial part for the documentation is the “_.set(_validator, [docsLib.propSymbols.validation, target], schema)“ part. This will set a property onto the middleware function, which we can later extract for documentation. The same principle applies to error and response validation.
Now that we know how to extract the schemas, we just need to get all the middleware in the application. In order to do this we just require our application configuration “app.js” and look into the “middleware” property.
“FetchRouter” will extract all the routers in a koa application that uses koa-router, then we iterate through all of them, create a swagger style object with the help of joi-to-swagger module and voila you have yourself documentation for your routes.
There are two other documentation sections that combined create the final documentation.
- Base.yaml -> this is the base documentation for the application. Information like application name, description, authorization types, server urls etc.
- Extended section -> this part is intended to write up detailed descriptions for every route and works by combining it with the automatically generated docs. The way this part would be added is by mimicking the route structure you have and creating a similar structure in the documentation. ( This part will probably get removed and done entirely through middleware )
The final documentation is a combination of “base.yaml”, route validations and the extended documentation. An example can be found here with an additional readme on how to use it.
I hope this frees up more time for your development as it has for ours. Happy coding!