Usage of Swagger 2.0 in Spring Boot Applications to document APIs

As IBM VP Angel Diaz stated in an interview on SearchCloudComputing “Swagger is the way most developers describe [REST] APIs”. With version 2.0 many important features like extensibility have been added, there is a big community and many developers are using it by now. Additionally there is work going on to create an open governance model around the Swagger specification under the Linux Foundation as part of the Open API Initiative.

What I like most about Swagger is the ability to document APIs directly in the (Java) source code via annotations so that documentation and actual API implementations are not out of synch.

IBM uses Swagger for the API documentation of several products and services internally. Furthermore the API management service in IBM Bluemix can import Swagger 2.0 definitions to manage your APIs easily.

The Java Spring framework has a lot of traction in the enterprise community these days. In order to use Swagger in Spring Boot applications I tried Springfox which is not part of Swagger core but it integrates nicely in Spring and supports the core Swagger annotations.

Below I extended the Spring sample Building a RESTful Web Service with Swagger annotations.

First you need to define the dependencies to the Springfox and Swagger libraries, in my case in Maven.

<?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>org.springframework</groupId>
	<artifactId>gs-rest-service</artifactId>
	<version>0.1.0</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.0.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.2.2</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.2.2</version>
			<scope>compile</scope>
		</dependency>
	</dependencies>

	<properties>
		<java.version>1.8</java.version>
	</properties>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-releases</id>
			<url>https://repo.spring.io/libs-release</url>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-releases</id>
			<url>https://repo.spring.io/libs-release</url>
		</pluginRepository>
	</pluginRepositories>
</project>

Then I enabled Swagger in the boot application.

package hello;

import static springfox.documentation.builders.PathSelectors.regex;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.google.common.base.Predicate;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2
@ComponentScan("hello")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @Bean
    public Docket newsApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("greetings")
                .apiInfo(apiInfo())
                .select()
                .paths(regex("/greeting.*"))
                .build();
    }
    
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring REST Sample with Swagger")
                .description("Spring REST Sample with Swagger")
                .termsOfServiceUrl("http://www-03.ibm.com/software/sla/sladb.nsf/sla/bm?Open")
                .contact("Niklas Heidloff")
                .license("Apache License Version 2.0")
                .licenseUrl("https://github.com/IBM-Bluemix/news-aggregator/blob/master/LICENSE")
                .version("2.0")
                .build();
    }
}

In the controller I used Swagger annotations to document the API.

package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @ApiOperation(value = "getGreeting", nickname = "getGreeting")
    @RequestMapping(method = RequestMethod.GET, path="/greeting", produces = "application/json")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "name", value = "User's name", required = false, dataType = "string", paramType = "query", defaultValue="Niklas")
      })
    @ApiResponses(value = { 
    		@ApiResponse(code = 200, message = "Success", response = Greeting.class),
    		@ApiResponse(code = 401, message = "Unauthorized"),
    		@ApiResponse(code = 403, message = "Forbidden"),
    		@ApiResponse(code = 404, message = "Not Found"),
    		@ApiResponse(code = 500, message = "Failure")})	
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(),
        		String.format(template, name));
    }
}

In the sample resource I documented parameters.

package hello;

import com.fasterxml.jackson.annotation.JsonProperty;

import io.swagger.annotations.ApiModelProperty;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    @JsonProperty(required = true)
    @ApiModelProperty(notes = "The name of the user", required = true)
    public String getContent() {
        return content;
    }
}

Here is the outcome in the API explorer.

swaggerspring

  • Pingback: Usage of Swagger 2.0 in Spring Boot Applications to document APIs | Dinesh Ram Kali.()

  • Pingback: Deploying Spring Boot Applications to Bluemix()

  • Pingback: Management of APIs with IBM Bluemix()

  • Pingback: This week in API land #29 | Restlet - We Know About APIs()

  • Pingback: Usage of Swagger in Node.js Applications to document APIs()

  • Pingback: Usage of Swagger in NodeJS Applications to document APIs | Dinesh Ram Kali.()

  • Arthur De Magalhaes

    Hey, great post.

    Have you tried Liberty’s latest December Beta? https://developer.ibm.com/wasdev/blog/2015/11/20/beta-was-liberty-beta-with-tools-december-2015/

    The new apiDiscovery-1.0 feature will let Liberty auto-generate a Swagger document from your jaxrs app’s annotations (including Swagger 2.0 annotations). You can then view it through a UI (/ibm/api/explorer), just like StrongLoop and Swagger’s Petstore sample.

    Here’s the doc: http://www-01.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_api_discovery.html

    You could package that server and deploy to Bluemix. Or, you could hook up the API-Management service from Bluemix to your Liberty instance by importing the /ibm/api/docs URL from your Liberty server (it is a valid Swagger 2.0 JSON doc)

    – Arthur

    • Niklas Heidloff

      Cool. Didn’t know this. Thanks for sharing, Arthur.

      • Pavan Kumar

        /swagger-ui.html is not comings.
        Showing like below..
        There was an unexpected error (type=Method Not Allowed, status=405).

        Request method ‘GET’ not supported

  • Marcel Overdijk

    Niklas Heidloff Swagger intrigued me at the beginning as it generated nice looking docs quickly.

    However it takes a lot of duplication in the *code*.
    E.g. @RequestParam and @ApiImplicitParam containing both the name.
    And also the @ApiResponse annotations have to be added each time.

    It’s not only that the code is bloated with a lot of annotations, also keeping them in sync can be a real pain.
    How is dealt with this at IBM?

    • Niklas Heidloff

      I agree. Not perfect. I don’t have a good answer.

  • David Amend

    Is there a full working code example in the github? Without a test, no files are generated

    • Niklas Heidloff

      Sorry, didn’t publish on GitHub. All code changes to the Spring sample “Building a RESTful Web Service” should be in the blog though.

  • Sudhashri S Hebbar

    How do we get the output in the Swagger UI?

    • Niklas Heidloff

      Sorry, no time to check. From the top of my head I used these URLs:
      /greeting
      /v2/api-docs?group=greetings
      /swagger-ui.html

      • Sudhashri S Hebbar

        Thank you.

      • VKKS

        I thought this article will help understand swagger, as it is dependencies and some annotations. But it did not work. I wish people write article with usage [url].

  • Ína Be

    Amazing! thx!

  • Barbora Červenková

    Is there any possibility to add description to the place where “Response Class (Status 200)” is? This is only feature what I really miss there.

    • Niklas Heidloff

      Barbora, if I understand you correctly, this is possible but I don’t know how from the top of my head. Here is an example which might help: https://watson-api-explorer.mybluemix.net/apis/tone-analyzer-v3-beta#!/tone/get_v3_tone

      • Barbora Červenková

        thanks for answer, in fact I was looking for @ApiOperation(notes = “Here is description of endpoint”)

        • Barbora Červenková

          And one more question, did you manage to add to swagger response headers? I tried this,but in UI is nothing @ResponseHeader(name = “location”, description = “URI of created resource”) }

  • N Pathrut

    I received the below response when i tried to access the Swagger doc:

    Whitelabel Error Page

    This application has no explicit mapping for /error, so you are seeing this as a fallback.

    Mon Apr 18 18:14:35 IST 2016

    There was an unexpected error (type=Not Found, status=404).

    No message available

    Please help some into this.

  • pravinuttarwar

    Great Post. We are also using Swagger but we want to know best way to handle API versioning and it would be great if you can tell how IBM is handling it for internal projects.

  • Gahininath shinde

    thanks for providing such useful post. I have one query..what is the datatype for enum parameter. I checked with enum,Enum but it doesn’t identified it.

  • Gahininath shinde

    Hi,

    I facing a problem while sending object in request payload through swagger:
    My scenario is like this:
    I have User class contains 10 fields, out of which my API required 4 fields to update my DB, but In currently it showing all 10 fields in request payload which may confuse API caller. Is there any ways to show only required fields in request payload in model schema.

    Please help me to solve this issue.

    Regards,
    Gahininath

  • youkuan

    usage of Swagger2.0 in Spring boot and Jersey2.x restful api,How can we achieve it?

    Swagger2.0 whether to support Jersey’s tag mapping?

  • youkuan

    My understanding Spring Boot load Swagger Ui, next Spring Boot load Jersey ,next Swagger Mapping Jersey Tag and Display,My understanding is correct.?

    If my understanding is correct ,can you tell me how to do it?

  • omar salem

    Great example
    but would’ve been better if you mentioned how to see the output through /swagger-ui.html
    Thanks

  • Neha

    Will these configuration worked in Spring MVC + Swagger code too ?

  • Chris Hankey

    Are there any Swagger implementations besides Springfox for Spring MVC REST services? I’ve found Springfox to be very buggy.

  • Chabchoub Iheb

    Hello , I’m getting a blank page at first , then when trying to search for something I get failed to parse JSON/YAML response, any help ?

  • letorn

    the @API annotation didn’t work in swagger-2.6, how can I write note on the controller class?