Microservices API Documentation with Swagger2
Swagger is the most popular tool for designing, building and documenting RESTful APIs. It has nice integration with Spring Boot. To use it in conjunction with Spring we need to add the following two dependencies to Maven pom.xml
.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
Swagger configuration for a single Spring Boot service is pretty simple. The level of complexity is greater if you want to create one documentation for several separated microservices. Such documentation should be available on API gateway. In the picture below you can see the architecture of our sample solution.
First, we should configure Swagger on every microservice. To enable it we have to declare @EnableSwagger2
on the main class. API documentation will be automatically generated from source code by Swagger library during application startup. The process is controlled by Docket
@Bean
which is also declared in the main class. The API version is read from pom.xml
file using MavenXpp3Reader
. We also set some other properties like title, author and description using apiInfo method. By default, Swagger generates documentation for all REST services including those created by Spring Boot. We would like to limit documentation only to our @RestController
located inside pl.piomin.microservices.advanced.account.api package.
@Bean
public Docket api() throws IOException, XmlPullParserException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileReader("pom.xml"));
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("pl.piomin.microservices.advanced.account.api"))
.paths(PathSelectors.any())
.build().apiInfo(new ApiInfo("Account Service Api Documentation", "Documentation automatically generated", model.getParent().getVersion(), null, new Contact("Piotr Mińkowski", "piotrminkowski.wordpress.com", "piotr.minkowski@gmail.com"), null, null));
}
Here’s our API RESTful controller.
@RestController
public class AccountController {
@Autowired
AccountRepository repository;
protected Logger logger = Logger.getLogger(AccountController.class.getName());
@RequestMapping(value = "/accounts/{number}", method = RequestMethod.GET)
public Account findByNumber(@PathVariable("number") String number) {
logger.info(String.format("Account.findByNumber(%s)", number));
return repository.findByNumber(number);
}
@RequestMapping(value = "/accounts/customer/{customer}", method = RequestMethod.GET)
public List findByCustomer(@PathVariable("customer") String customerId) {
logger.info(String.format("Account.findByCustomer(%s)", customerId));
return repository.findByCustomerId(customerId);
}
@RequestMapping(value = "/accounts", method = RequestMethod.GET)
public List findAll() {
logger.info("Account.findAll()");
return repository.findAll();
}
@RequestMapping(value = "/accounts", method = RequestMethod.POST)
public Account add(@RequestBody Account account) {
logger.info(String.format("Account.add(%s)", account));
return repository.save(account);
}
@RequestMapping(value = "/accounts", method = RequestMethod.PUT)
public Account update(@RequestBody Account account) {
logger.info(String.format("Account.update(%s)", account));
return repository.save(account);
}
}
The similar Swagger’s configuration exists on every microservice. API documentation UI is available under /swagger-ui.html. Now, we would like to enable one documentation embedded on the gateway for all microservices. Here’s Spring @Component
implementing SwaggerResourcesProvider
interface which overrides default provider configuration exists in Spring context.
@Component
@Primary
@EnableAutoConfiguration
public class DocumentationController implements SwaggerResourcesProvider {
@Override
public List get() {
List resources = new ArrayList<>();
resources.add(swaggerResource("account-service", "/api/account/v2/api-docs", "2.0"));
resources.add(swaggerResource("customer-service", "/api/customer/v2/api-docs", "2.0"));
resources.add(swaggerResource("product-service", "/api/product/v2/api-docs", "2.0"));
resources.add(swaggerResource("transfer-service", "/api/transfer/v2/api-docs", "2.0"));
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
All microservices api-docs are added as Swagger resources. The location address is proxied via Zuul gateway. Here’s gateway route configuration.
zuul:
prefix: /api
routes:
account:
path: /account/**
serviceId: account-service
customer:
path: /customer/**
serviceId: customer-service
product:
path: /product/**
serviceId: product-service
transfer:
path: /transfer/**
serviceId: transfer-service
Now, API documentation is available under gateway address http://localhost:8765/swagger-ui.html. You can see how it looks for the account-service in the picture below. We can select the source service in the combo box placed inside the title panel.
Documentation appearance can be easily customized by providing UIConfiguration
@Bean
. In the code below I changed default operations expansion level by setting “list” as a second constructor parameter – docExpansion.
@Bean
UiConfiguration uiConfig() {
return new UiConfiguration("validatorUrl", "list", "alpha", "schema",
UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, false, true, 60000L);
}
You can expand every operation to see the details. Every operation can be test by providing required parameters and clicking Try it out! button.
Sample application source code is available on GitHub.
42 COMMENTS