Aggregate Services into a Single Swagger
By now most companies that have pointed their ship towards some sort of service architecture (in buzz words, microservices) have also discovered an API explorer to ease the pains of developers that are trying to consume services that they know nothing about. Swagger is a popular option when it comes to self-documenting API explorers. In Spring Boot, with a matter of two dependencies and a little configuration you can be running with a “Swagger” endpoint to hit that exposes all available REST endpoints.
This is great, no doubt. However, when you start to expand to more than a handful of services it can become cumbersome to keep track of each service’s Swagger page. Also, depending on how your load balancer is set up it may be hard to target an individual service’s Swagger page from behind the load balancer. For these reasons and a bit of curiosity, I decided to explore aggregating multiple swaggers into their own service. The rest of this post will illustrate how to go about doing this so that you can have a single Swagger that looks something like the image below.
Swagger already has support for aggregating multiple service’s API documentation, which they call “resources”. It’s just a matter of knowing where to look and what to override. To get started I stood up a very basic Spring Boot service that includes the normal swagger dependencies (shown below). The snippets throughout the post are pulled from my full project on GitHub, swagger-aggregate.
The only piece that is absolutely necessary to make this work is to create a class that overrides the SwaggerResourcesProvider. It expects an implementation of get() that returns a set of SwaggerResource objects. These point the aggregate to the various Swagger endpoints by providing the service name, url of the api-docs, and the version of Swagger it’s running. In my sample application, I pushed these definitions into the application.yml file and pulled them into a custom object using the @ConfigurationProperties annotation. This is not needed but felt like a good chance to push the configuration out of the code.
To add a new service to the aggregate you simply update the application.yml file with the details of the service’s Swagger. You can define absolute urls pointing to the api-docs or relative if they share the same domain. The example project is pointing directly at the Swagger’s Petstore example docs so that the project actually has some content if you run it.
With services behind a load balancer, it’s possible all of their api-docs might be at the same /v2/api-docs endpoint. If you need to get around this you can customize the api-docs path to be more specific to the service.
The last thing you may notice in the example project is a small redirect endpoint that points /swagger to /swagger-ui.html. It’s always felt unneeded to type that extra ‘-ui.html’, so this fixes that.
Are there ways you’d improve this? Hook it up to service discovery? Enable authentication at the aggregate level?
The source for this project can be found on GitHub.