Spring REST + Swagger 2 Example

By Arvind Rai, June 24, 2019
This page will walk through Spring REST and Swagger 2 integration with annotation and XML example. Swagger is API specification for documentation in web service. Swagger can generate documentation, API clients and server stubs in different languages by parsing Swagger definition. Swagger also provides UI that represents documentation. Swagger provides specification and we will use SpringFox implementation in our example. Using Swagger it becomes easy to understand REST web service methods for a client because using Swagger UI we get all information of web service methods with description about what the method does. We can also test web services method from Swagger UI. In our example we will integrate Swagger in our Spring REST web service application to get REST web service method documentation. We can also test REST web service methods using Swagger UI. In our example we are using SpringFox implementation of Swagger 2 specification. Here on this page we will provide complete example to integrate Swagger 2 with Spring REST web service using JavaConfig as well as XML configuration. Now find the complete example step by step.

Technologies Used

We are using following software in our example.
1. Java 8
2. Spring 4.3
3. Swagger 2
4. Gradle 3.3
5. Maven 3.3
6. Tomcat 8.0
7. Eclipse Mars

Step-1: Gradle and Maven to Resolve Swagger API

To work with Swagger documentation, we need to use springfox-swagger2 and springfox-swagger-ui API.
Find the Gradle to resolve Swagger API dependency.
dependencies {
    compile 'io.springfox:springfox-swagger2:2.7.0'        
    compile 'io.springfox:springfox-swagger-ui:2.7.0'    
}
Find the Maven to resolve Swagger API dependency.
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.7.0</version>		
</dependency>
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.7.0</version>		
</dependency> 

Step-2: Enable Swagger 2 using @EnableSwagger2 Annotation

To enable Swagger 2 we need to annotate configuration class with @EnableSwagger2 .
@Configuration 
@EnableSwagger2
public class SwaggerConfig {

}
All the default configuration is enabled now just by using @EnableSwagger2 annotation. For custom implementation, we need to create a method with return type Docket annotated with @Bean.
In case we are using XML configuration, we need to create a bean of the above class.
<bean class="com.concretepage.config.SwaggerConfig"/> 

Step-3: Swagger UI Endpoint Configuration

Find the configuration to expose Swagger UI endpoint /swagger-ui.html and /v2/api-docs in Spring MVC configuration file.
Find the configuration using JavaConfig. We need to override addResourceHandlers() method of WebMvcConfigurerAdapter. If we are not using Spring boot, our Spring MVC configuration class needs to be annotated with @EnableWebMvc. Now find the addResourceHandlers() method definition.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
        .addResourceLocations("classpath:/META-INF/resources/");
    registry.addResourceHandler("/webjars/**")
        .addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Find the XML configuration.
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/"/>
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/> 
Now we are ready to test the application with default Swagger 2 configuration. Suppose application context is spring-app then we need to append /swagger-ui.html to get Swagger UI and append /v2/api-docs to get JSON response of API documentation.
1. URL for Swagger UI.
http://localhost:8080/spring-app/swagger-ui.html
Spring REST + Swagger 2 Integration with Annotation + XML Example
2. URL to get JSON Response of API documentation.
http://localhost:8080/spring-app/v2/api-docs
Spring REST + Swagger 2 Integration with Annotation + XML Example

Docket Custom Implementation

Docket is a builder that provides default configuration of Swagger documentation. If we want custom implementation, then we need to create a method in Swagger configuration class with return type Docket annotated with @Bean.
@Configuration 
@EnableSwagger2
public class SwaggerConfig {
   @Bean
   public Docket customImplementation(){
      return new Docket(DocumentationType.SWAGGER_2)
    	  .select()
	  .apis(RequestHandlerSelectors.basePackage("com.concretepage"))
	  .paths(PathSelectors.any())
	  .build();
   }
} 
In the constructor of Docket we are passing configuration for Swagger 2. select() method returns ApiSelectorBuilder that is used to control end points. apis() method allows selection of request handler. Request handler can be any, none, basePackage etc. The method paths() is used to allow selection of path using predicate. In our example we are using any predicate that is default. After configurations, we need to build the selector using build() method. If we want to set custom meta information, we need use apiInfo() method as following.
@Configuration 
@EnableSwagger2
public class SwaggerConfig {
   @Bean
   public Docket customImplementation(){
      return new Docket(DocumentationType.SWAGGER_2)
    	  .apiInfo(getApiInfo())	  
    	  .select()
          .apis(RequestHandlerSelectors.basePackage("com.concretepage"))
          .paths(PathSelectors.any())
          .build();
   }
   private ApiInfo getApiInfo() {
	   return new ApiInfo("REST Api Documentation",
	      "REST Api Documentation", 
	      "1.0", 
	      "urn:tos",
	       new Contact("", "", ""), 
              "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", 
              new ArrayList<VendorExtension>());
   }
}

Swagger Annotations for Documentation from Property File Lookup

Swagger provides annotation to provide custom documentation for REST web service methods. Documentation messages can be externalized and can be looked up from property file. Find the annotations.
@ApiOperation: Provides documentation for REST web service method, for example what operation this method performs.
@ApiParam: Provides documentation about parameter of REST web service method.

Find the example.
@GetMapping("article/{id}")
@ApiOperation(value = "Get Article by Id", notes = "${ArticleController.getArticleById.notes}")
public ResponseEntity<Article> getArticleById(
	@ApiParam(value = "${ArticleController.getArticleById.id}", required = true) 
        @PathVariable("id") Integer id) {
	
	Article article = articleService.getArticleById(id);
	return new ResponseEntity<Article>(article, HttpStatus.OK);
}
Find the property file for the example.
documentation.properties
ArticleController.getArticleById.notes= Pass article Id and the REST web service method will return an article.
ArticleController.getArticleById.id= The values of Id can be 1,2 etc.
ArticleController.getArticleById.id.default= 1 
After running Swagger UI, we will get documentation messages as follows.
Spring REST + Swagger 2 Integration with Annotation + XML Example
There are more Swagger annotations for documentation.
@ApiImplicitParams: This is the wrapper for @ApiImplicitParam annotation.
@ApiImplicitParam: Represents a single parameter in an API operation and is used within @ApiImplicitParams to provide documentation for REST web service method parameter. @ApiParam is also used to provide documentation but it is bound to JAX-RS parameter.

Find the example.
@PutMapping("article")
@ApiOperation(value = "Update Article", notes = "${ArticleController.updateArticle.notes}")
@ApiImplicitParams(
   @ApiImplicitParam(name="article", value="${ArticleController.updateArticle.article}") 
)		
public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
    articleService.updateArticle(article);
    return new ResponseEntity<Article>(article, HttpStatus.OK);
}
Find the properties.
ArticleController.updateArticle.notes=  This REST web service method will update article.
ArticleController.updateArticle.article= Pass article with all fields.


Spring REST + Swagger 2 Integration Example using JavaConfig

Find the project structure.
Spring REST + Swagger 2 Integration with Annotation + XML Example
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
war.archiveName 'spring-app.war'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.5.6.RELEASE'
    compile 'io.springfox:springfox-swagger2:2.7.0'        
    compile 'io.springfox:springfox-swagger-ui:2.7.0'    
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.6.RELEASE'    
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>Spring</name>
	<description>Spring Demo Project</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>1.5.6.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>1.8</java.version>
	    <context.path>spring-app</context.path>
	</properties>
	<dependencies>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	  </dependency>
	  <dependency>
		<groupId>io.springfox</groupId>
		<artifactId>springfox-swagger2</artifactId>
	        <version>2.7.0</version>		
	  </dependency>
	  <dependency>
		<groupId>io.springfox</groupId>
		<artifactId>springfox-swagger-ui</artifactId>
	        <version>2.7.0</version>		
	  </dependency>	  	  
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-tomcat</artifactId>
		<scope>provided</scope>
	  </dependency>      
	</dependencies>
	<build>
	  <plugins>
	    <plugin>
		  <groupId>org.apache.maven.plugins</groupId>
		  <artifactId>maven-war-plugin</artifactId>
		  <version>3.0.0</version>
		  <configuration>
			 <warName>${context.path}</warName>
		  </configuration>
	    </plugin>
	  </plugins>
	</build>
</project> 
SwaggerConfig.java
package com.concretepage.config;
import java.util.ArrayList;
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.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.VendorExtension;
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 customImplementation(){
      return new Docket(DocumentationType.SWAGGER_2)
    	  .apiInfo(getApiInfo())	  
    	  .select()
	  .apis(RequestHandlerSelectors.basePackage("com.concretepage"))
	  .paths(PathSelectors.any())
	  .build();
   }
   private ApiInfo getApiInfo() {
      return new ApiInfo("REST Api Documentation",
	  "REST Api Documentation", 
	  "1.0", 
	  "urn:tos",
	   new Contact("", "", ""), 
	  "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", 
	   new ArrayList<VendorExtension>());
   }
} 
AppConfig.java
package com.concretepage.config;  
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc   
@PropertySource("classpath:documentation.properties")
public class AppConfig extends WebMvcConfigurerAdapter {  
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    } 
} 
WebAppInitializer.java
package com.concretepage.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { AppConfig.class };
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}
	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
} 
Article.java
package com.concretepage.domain;
public class Article { 
    private int articleId;  
    private String title;
	private String category;
	public Article() {}	
	public Article(int articleId, String title, String category) {
		this.articleId = articleId;
		this.title = title;
		this.category = category;
	}
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
}  
IArticleService.java
package com.concretepage.service;
import java.util.List;
import com.concretepage.domain.Article;
public interface IArticleService {
     List<Article> getAllArticles();
     Article getArticleById(int articleId);
     boolean addArticle(Article article);
     void updateArticle(Article article);
     void deleteArticle(int articleId);
} 
ArticleService.java
package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.stereotype.Service;
import com.concretepage.domain.Article;
@Service
public class ArticleService implements IArticleService {
	private List<Article> list = new ArrayList<>();
	{
		list.add(new Article(1, "Angular 2 Tutorial using CLI", "Angular"));
		list.add(new Article(2, "Spring Boot Getting Started", "Spring Boot"));
		list.add(new Article(3, "Lambda Expressions Java 8 Example", "Java 8"));
	}
	@Override
	public Article getArticleById(int articleId) {
		Predicate<Article> articlePredicate = a-> a.getArticleId() == articleId;
		Article obj = list.stream().filter(articlePredicate).findFirst().get();
		return obj;
	}	
	@Override
	public List<Article> getAllArticles(){
	        return list;
	}
	@Override
	public boolean addArticle(Article article){
	        list.add(article);	   
	        return true;
	}
	@Override
	public void updateArticle(Article article) { 
		Predicate<Article> articlePredicate = a-> a.getArticleId() == article.getArticleId();
		Article obj = list.stream().filter(articlePredicate).findFirst().get();
		obj.setTitle(article.getTitle());
		obj.setCategory(article.getCategory());
	}
	@Override
	public void deleteArticle(int articleId) {
		Predicate<Article> articlePredicate = a-> a.getArticleId() == articleId;
		Article obj = list.stream().filter(articlePredicate).findFirst().get();		
		list.remove(obj);
	}
} 
ArticleController.java
package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.domain.Article;
import com.concretepage.service.IArticleService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@Controller
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;
	
	@GetMapping("article/{id}")
	@ApiOperation(value = "Get Article by Id", notes = "${ArticleController.getArticleById.notes}")
	public ResponseEntity<Article> getArticleById(
		@ApiParam(value = "${ArticleController.getArticleById.id}", required = true) 
	        @PathVariable("id") Integer id) {
		
		Article article = articleService.getArticleById(id);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@PutMapping("article")
	@ApiOperation(value = "Update Article", notes = "${ArticleController.updateArticle.notes}")
	@ApiImplicitParams(
	   @ApiImplicitParam(name="article", value="${ArticleController.updateArticle.article}") 
	)		
	public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
		articleService.updateArticle(article);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}	
	@GetMapping("articles")
	public ResponseEntity<List<Article>> getAllArticles() {
		List<Article> list = articleService.getAllArticles();
		return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
	}
	@PostMapping("article")
	public ResponseEntity<Void> addArticle(@RequestBody Article article, UriComponentsBuilder builder) {
                boolean flag = articleService.addArticle(article);
                if (flag == false) {
        	    return new ResponseEntity<Void>(HttpStatus.CONFLICT);
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
	@DeleteMapping("article/{id}")
	public ResponseEntity<Void> deleteArticle(@PathVariable("id") Integer id) {
		articleService.deleteArticle(id);
		return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
	}	
} 
documentation.properties
ArticleController.getArticleById.notes= Pass article Id and the REST web service method will return an article.
ArticleController.getArticleById.id= The values of Id can be 1,2 etc.
ArticleController.getArticleById.id.default= 1

ArticleController.updateArticle.notes=  This REST web service method will update article.
ArticleController.updateArticle.article= Pass article with all fields. 

Spring REST + Swagger 2 Integration Example using XML Configuration

Find the project structure.
Spring REST + Swagger 2 Integration with Annotation + XML Example
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
        
	<context:component-scan base-package="com.concretepage" />

	<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/"/>
        <mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
        <bean class="com.concretepage.config.SwaggerConfig"/>
      
        <bean name="jackson2ObjectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
	    <property name="indentOutput" value="true"/>
	</bean>    
	<mvc:annotation-driven>
	    <mvc:message-converters>
	        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
	            <property name="objectMapper" ref="jackson2ObjectMapper" />
	        </bean>
	    </mvc:message-converters>
	</mvc:annotation-driven>    
</beans> 
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

	<display-name>Spring 4 REST Example</display-name>
	<context-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>
	       /WEB-INF/dispatcher-servlet.xml
	    </param-value>		    
	</context-param>	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
		    org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>  

Test Demo Application

To build and run the demo application, follow the steps.
1. Download the source code from the link given below on this page.
2. Go to the root directory of the project using command prompt.
3. Build the project using gradle with following command.
gradle clean build 
We can find WAR file in the build\libs directory. If we want to build the project using maven, use following command.
mvn clean package 
We can find WAR file in the target directory.
4. Deploy the WAR file in tomcat.

a. URL for Swagger UI.
http://localhost:8080/spring-app/swagger-ui.html
b. URL to get JSON Response of API documentation.
http://localhost:8080/spring-app/v2/api-docs

Reference

Springfox Reference Documentation

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us