Writing documentation is a necessity which is extremely dull and boring. But luckily there is a tool available referred to as Swagger API Documentation. Documentation with Swagger has never been easier. All you have to do is to add the dependency to your Spring Boot project and Swagger will take care of it for you.
Swagger API Documentation
Dependencies
In order to get started, we are going to add two dependencies to our project.
io.springfox
springfox-swagger2
2.7.0
The first one, springfox-swagger2
, is the one that does the actual job, it gathers all your endpoints and checks the request parameters and bodies, as well as the responses in order to give examples of how the endpoints are used. Think of it as the brain.
io.springfox
springfox-swagger-ui
2.7.0
The second dependency, springfox-swagger-ui
is the face of swagger. When enabling this dependency, swagger will publish some new endpoints for us where it will present the API documentation in a nice and pleasant format for the eye.
Swagger Configuration
With that done, all that’s left to do is for us to configure Swagger. You can do quite a lot of custom configuration but the bare minimum config that we are going to need is something similar to the following.
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
This configuration means that we are basically going to publish all of our API endpoints to the documentation and we also specify that we should use Swagger2 as the type of our documentation. Swagger also has a version 1, if you would prefer to stick to that for some reason.
After creating the configuration, you should now be able to reach the Swagger UI page where you can see documentation of your API. Head to http://localhost:/swagger-ui.html
Adding Custom Documentation
Most of the documentation for Swagger is generated automatically so that you don’t have to bother with it. But there are some options for customization.
We can for example add a custom description for our controllers by using the @Api
annotation. Let’s do that.
@Api(value="person", description = "Operations for persons in the system")
In a similar way, we can also customize the documentation for the different endpoints by using the @ApiOperation
annotation.
@ApiOperation(value= "Retrieves a person from the system if he or she exists", response = Person.class)
@GetMapping("/person/{name}")
public ResponseEntity getPerson(@PathVariable String name) {
Optional person = personRepository.findById(name);
if (person.isPresent()) {
return ResponseEntity.ok(person.get());
} else {
return ResponseEntity.badRequest().body(null);
}
}
We can also customize the response messages by providing one, or many @ApiResponse
‘s.
@ApiOperation(value= "Retrieves a person from the system if he or she exists", response = Person.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successfully retrieved person"),
@ApiResponse(code = 401, message = "You are not authorized to view the person resource"),
@ApiResponse(code = 403, message = "Accessing the person resource you were trying to reach is forbidden"),
@ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
})
@GetMapping("/person/{name}")
public ResponseEntity getPerson(@PathVariable String name) {
Optional person = personRepository.findById(name);
if (person.isPresent()) {
return ResponseEntity.ok(person.get());
} else {
return ResponseEntity.badRequest().body(null);
}
}
)
Skip Publishing Internal APIs
You might have some internal APIs that you don’t want to expose, or in our case we had that ugly ErrorController that we don’t really want to show. So let’s add some configuration so that we only expose our actual API that we want to expose.
There are different ways to do this, but my favourite way is to specify the paths in the configuration. We are going to add a @RequestMapping("/api")
to our Person controller. And we are also going to edit our Swagger configuration to add paths matching a regex that we specify.
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(regex("/api/.*"))
.build();
}
}
Swagger with Spring Framework 5 and Spring Boot 2
Worth keeping in mind if you have upgraded to Spring Boot 2 and/or Spring Framework 5 is that the Swagger API Documentation might not worth out of the box without some additional configuration.
In order to make Swagger work with Spring Framework 5 and Spring Boot 2 your Swagger configuration will have to extend WebMvcConfigurationSupport
and add two resource handlers.
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Final words
We have looked at how we can use Swagger2 to make the boring, but required work of documentation a lot more fun, easy and convenient. Swagger API Documentation is really great and you should give it a try. The bigger your project gets, the more you are going to appreciate having the documentation written for you automatically.
The code for this project is available at my GitHub.
Nice Post. I have a couple of questions
1. Can I execute springfox-swagger2 in a standalone fashion through some command line by feeding it the path to the project source files as input and expecting an open api specification as the output?
2. Can it parse javax-ws-rs annotation to generate open api specification?
Thanks!