Building REST APIs with Spring Boot and SpringFox/Swagger

This blog post demonstrates step by step how to develop RESTful APIs using Spring Boot and then how to document and expose the API via Swagger (OpenAPI)  specification using SpringFox.

Project Setup

The project is a Spring Boot web application, e.g. created with Spring Initializr, with the following dependencies (in Maven):

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

I am using Spring Data backed by MongoDB data store here. We can also use a relational database such as MySQL instead.

To use SpringFox, we also need to add the following:

		<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>

The first dependency is required to add SpringFox support for Swagger 2 to the project. The second dependency adds swagger-ui, which is a GUI framework for displaying the API documentation as part of the web application.

Product API

We are going to build a very simple CRUD API for product resources.

@Document(collection = "product")
public class Product {

     @Id
     private String id;
     private String sku;
     private String description;
     private BigDecimal price;
...

The entity is to be persisted to a MongoDB collection product as denoted by the @Document annotation. This is implemented with Spring Data using the MongoRepository

// ProductRepository.java
import org.springframework.data.mongodb.repository.MongoRepository;
...

public interface ProductRepository extends MongoRepository<Product, String> {

}

The above repository is accessed by the controller via the service layer as defined by the following interface

public interface ProductService {
	Product read(String id);	
	Product update(String id, Product product);
	Product create(Product product);
	void delete(String id);
}

Finally, the rest controller implemented with Spring MVC

// ProductController.java - plain old Spring MVC
@RestController
@RequestMapping("/product")
public class ProductController {

	@Autowired
	private ProductService service;

	@PostMapping(value = "")
	public Product create(@RequestBody Product product) {
		return service.create(product);
	}

	@GetMapping(value = "/{id}")
	public Product read(@PathVariable("id") String id) {
		return service.get(id);
	}

	@PatchMapping(value = "/{id}")
	public Product update(@PathVariable("id") String id, @RequestBody Product product) {
		return service.update(id, product);
	}

	@DeleteMapping(value = "/{id}")
	public void delete(@PathVariable("id") String id) {
		service.delete(id);
	}
}

Swagger with SpringFox

So far, we have a standard Spring Boot web application which can serve the product API. To use Swagger with SpringFox, we will need to update the codes as follows:

Configuration

@Configuration
@EnableSwagger2
public class SpringFoxConfig {

     // Inject API info property values
     @Value("${api.title}")
     private String title;
     ...

     @Bean
     public Docket apiDocket() {
          //@formatter:off
          return new Docket(DocumentationType.SWAGGER_2)
                     .select()
                     .apis(RequestHandlerSelectors.basePackage("com.madman.bootswagger.controller"))
                     .paths(PathSelectors.any())
                     .build()
                     .apiInfo(getApiInfo());
          //@formatter:on
      }

     private ApiInfo getApiInfo() {
     //@formatter:off
          return new ApiInfo(
                     title,
                     description,
                     version,
                     termOfServiceUrl,
                     new Contact(contactName, contactUrl, contactEmail),
                     "LICENSE",
                     "LICENSE URL",
                     Collections.emptyList()
           );
      //@formatter:on
     }
}

The configuration setup is rather straight forward. All is needed is to declare the @EnableSwagger2 annotation to indicate Swagger support should be enabled and a Docket bean as builder into SpringFox. Note we restrict the apis scanning to the controller package.

ProductController with Swagger

The controller has been updated with SpringFox as below with the changes highlighted:

// ProductController.java with Swagger
@RestController
@RequestMapping("/product")
@Api(value = "products")
public class ProductController {

     @Autowired
     private ProductService service;

     @PostMapping(value = "/")
     public Product create(Product product) {
          return service.create(product);
     }

     @GetMapping(value = "/{id}")
     public Product read(@ApiParam(value = "product id", required = true) @PathVariable("id") String id) {
          return service.get(id);
     }

     @PatchMapping(value = "/{id}")
     public Product update(@ApiParam(value = "product id", required = true) @PathVariable("id") String id, 
                           @ApiParam(value = "product", required = true) @RequestBody Product product) {
          return service.update(id, product);
     }

     @DeleteMapping(value = "/{id}")
     public void delete(@ApiParam(value = "product id", required = true) @PathVariable("id") String id) {
          service.delete(id);
     }
}

The @Api annotation at the class level tells SpringFox to scan the class methods for API documentation.

Product model document

Finally, it is possible to annotate entity class to generate more appropriate documentation in Swagger using the @ApiModal and @ApiModelProperty annotations

@Document(collection = "product")
@ApiModel(description = "Product model")
public class Product {

@Id
@ApiModelProperty(value = "id in mongodb store", accessMode = AccessMode.READ_ONLY)
private String id;

@ApiModelProperty(value = "stock keeping unit")
private String sku;

@ApiModelProperty(value = "product description")
private String description;

@ApiModelProperty(value = "product base price")
private BigDecimal price;

Product API Specification

Now fire up Spring Boot and open the Swagger UI url (http://localhost:8080/swagger-ui.html) should display something like the screenshot below

blog_swagger

The above GUI display the API documentation as set by the annotations in the domain model and the controller. More importantly, the link http://localhost:8080/v2/api-docs provides the Swagger API specifications which the API clients can use in their development and testing.

Advertisements

About Raymond Lee
Professional Java/EE Developer, software development technology enthusiast.

Comments are closed.