Integrating Swagger 2 with Spring Boot 2 RESTful API in 2 Simple Steps

In the previous article we have implemented a Spring Boot REST CRUD API. Now we are gonna generate REST API Documentation using Swagger 2 for those RESTful services in 2 simple steps.

Introduction to Swagger

Swagger is a set of open-source tools built around the OpenAPI Specification that can help you design, build, document and consume REST APIs. It can generate both machine readable (JSON) and human readable (swagger-ui) documentation for RESTFul web services.

Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from an Open API Specification-compliant API like SpringFox.

SpringFox library integrates with Spring MVC with support for Swagger 1.2 and Swagger 2.0 spec. We are gonna use this tool to generate the documentation for our Spring RESTful web services.

Let’s Get Started

Step 1: Add Swagger dependencies

pom.xml

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>

Step 2: Configure Swagger 2

SwaggerConfig.java

SwaggerConfig is a Spring configuration class resposible for creating a Docket bean to configure the swagger

@EnableSwagger2 annotation indicates that Swagger support should be enabled

package com.javachinna.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
	@Bean
	public Docket api() {
		return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build();
	}
}

In this configuration class, the select() method called on the Docket bean instance returns an ApiSelectorBuilder

ApiSelectorBuilder provides the apis() and paths() methods to filter the controllers and methods that are being documented using String predicates.

Run with Maven

You can run the application using mvn clean spring-boot:run and hit the url http://localhost:8080/swagger-ui.html in the browser

The swagger ui will be displayed with all the controllers including in-built Spring’s BasicErrorController as shown below

swagger-ui

JSON Specification

The API dcoumentation in JSON format can be found in the link http://localhost:8080/v2/api-docs which is present below the title as shown below

json fromat api-docs

This is the default specification document generated by Swagger.

If you wanna customize the documentation further, then continue reading the following sections.

Filter Request Handlers and Endpoints

This section describes about various methods of selecting the Controllers / Endpoints for Swagger Documentation. However, we will stick to the first approach below in our application.

Select Request Handlers With Base Package

Since we are interested in our ProductController only, we can change the SwaggerConfig as shown below in order to document only our request handlers

@Bean
	public Docket api() {
		return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.javachinna")).paths(PathSelectors.any()).build();
	}

In the above code, the RequestHandlerSelectors.basePackage predicate matches the  com.javachinna  base package to filter the request handlers.

Select Request Handlers With Annotation

We can select the Controllers using annotation and add it to Swagger documentation with the following steps

Step 1: Create Annotation

package com.javachinna.config;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AddApiToSwagger {
}

Step 2: Add Annotation to the Controller

@AddApiToSwagger
public class ProductController implements ProductApi {

Step 3: Change SwaggerConfig Class

RequestHandlerSelectors.withClassAnnotation(AddApiToSwagger.class)

Select Methods With Annotation

We can also select the endpoint methods using annotation and add it to Swagger documentation with the following steps

Step 1: Create Annotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AddMethodToSwagger {
}

Step 2: Add Annotation to the Methods

	@Override
	@GetMapping("/products")
	@AddMethodToSwagger
	public List<Product> getProductList(@RequestParam String consumerKey) {

Step 3: Change SwaggerConfig Class

RequestHandlerSelectors.withMethodAnnotation(AddMethodToSwagger.class)

Select API Paths

When we need to include or exclude endpoints based on the path, then PathSelectors.ant and PathSelectors.regex predicates can be used instead of PathSelectors.any in the SwaggerConfig. For instance, the following predicate can be used to exclude the /products endpoints from the Swagger documentation and include endpoints with path /products/{productId} only.

PathSelectors.ant("/products/*")

Hide API

We can hide a Controller from Swagger Documentation using @ApiIgnore annotation as shown below

@ApiIgnore
public class ProductController implements ProductApi {

Configure API Meta Information

We are gonna configure API meta information like title, description, version etc., in our SwaggerConfig class using apiInfo method of Docket bean as shown below

@Bean
	public Docket api() {
		return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.javachinna")).paths(PathSelectors.any()).build().apiInfo(apiInfo());
	}

	private ApiInfo apiInfo() {
		return new ApiInfo("Product REST API", "Product API to perform CRUD opertations", "1.0", "Terms of service",
				new Contact("Java Chinna", "www.javachinna.com", "java4chinna@gmail.com"), "License of API", "API license URL", Collections.emptyList());
	}

The apiInfo() method returns ApiInfo object initialized with information about our API.

Add API Specific Information

The default generated API docs are good but they lack detailed API level information. We can add detailed information to the APIs using the following Swagger annotations.

@ApiMarks a class as a Swagger resource.
@ApiModelProvides additional information about Swagger models.
@ApiModelPropertyAdds and manipulates data of a model property.
@ApiOperationDescribes an operation or typically an HTTP method against a specific path.
@ApiParamAdds additional meta-data for operation parameters.
@ApiResponseDescribes a possible response of an operation.
@ApiResponsesA wrapper to allow a list of multiple ApiResponse objects.

Create interface with Swagger Annotations

In order to provide detailed API information using Swagger annotations, we are gonna create a new interface with abstract methods and have the Controller implement this interface.

This is done to keep the Swagger annotations separated from the Controller to make it clean and readable. You can add these annotations in the Controller itself if you want.

ProductApi.java

package com.javachinna.controller;

import java.util.List;

import com.javachinna.model.Product;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@Api
public interface ProductApi {

	@ApiOperation(value = "Get list of products in the System ", response = Iterable.class)
	@ApiResponses(value = { 
			@ApiResponse(code = 200, message = "Suceess"), 
			@ApiResponse(code = 401, message = "Not authorized!"), 
			@ApiResponse(code = 403, message = "Forbidden!"),
			@ApiResponse(code = 404, message = "Not found!") })
	public List<Product> getProductList(String consumerKey);

	@ApiOperation(value = "Get product by product ID", response = Product.class)
	public Product getProduct(Long productId);

	@ApiOperation(value = "Create product", response = String.class)
	public String createProduct(Product product);

	@ApiOperation(value = "Update product by product ID", response = String.class)
	public String updateProduct(Long productId, Product product);

	@ApiOperation(value = "Delete product by product ID", response = String.class)
	public String deleteProduct(Long productId);
}

By default, Swagger will document the possible responses based on the HTTP operation. You can use @ApiResponse annotation to change that as we have done for the Get list of products API

Implement Interface

We are gonna modify ProductController class to implement the ProductApi interface

public class ProductController implements ProductApi {

Add Swagger Model Information

We are gonna modify Product class to provide model information like example value, hidden, required or not etc., as shown below

@ApiModel
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@ApiModelProperty(hidden = true)
	private Long id;
	@ApiModelProperty(example = "Headset", required = true)
	private String name;
	@ApiModelProperty(example = "100", required = true)
	private String price;
}

Test Application

Now reload the page and expand the ProductController tab. All the endpoints will be listed with detailed information as shown below

Swagger UI with API information

Possible responses for Get All Products API

Possible responses for GET operation

Product Model Example Values

Product Model Example Values

@ApiModelProperty example value for List of objects field

To set example value for List of objects field, you can use the JSON string of List<Object> as shown below

	@ApiModelProperty(example = "[{   \"id\": 0,   \"name\": \"some name\" }, {   \"id\": 1,   \"name\": \"some other name\" }]", required = true)
	private List<Category> categories;

Swagger UI Output

@Apimodelproperty example with list of objects

Source Code

As always, you can get the source code from the Github below

https://github.com/JavaChinna/spring-boot-rest-swagger

Conclusion

That’s all folks! In this article, you’ve learned how to integrate Swagger with Spring Boot RESTful services.

I hope you enjoyed this article. Thank you for reading.

Read Next:  7 Steps to Secure Spring Boot 2 REST API with Spring Security Basic Authentication, Role based Authorization and MySQL Database

Leave a Reply