Over a million developers have joined DZone.
Platinum Partner

Documenting Your Spring API with Swagger

· Integration Zone

The Integration Zone is brought to you in partnership with 3scale. Discover why Rails + jspm >= ECMAScript 6 awesomeness.

Over the last several months, I've been developing a REST API using Spring Boot. My client hired an outside company to develop a native iOS app, and my development team was responsible for developing its API. Our main task involved integrating with Epic, a popular software system used in Health care. We also developed a Crowd-backed authentication system, based loosely on Philip Sorst's Angular REST Security.

To document our API, we used Spring MVC integration for Swagger (a.k.a. swagger-springmvc). I briefly looked into swagger4spring-web, but gave up quickly when it didn't recognize Spring's @RestController. We started with swagger-springmvc 0.6.5 and found it fairly easy to integrate. Unfortunately, it didn't allow us to annotate our model objects and tell clients which fields were required. We were quite pleased when a new version (0.8.2) was released that supports Swagger 1.3 and its @ApiModelProperty.

What is Swagger?
The goal of Swagger is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.

To demonstrate how Swagger works, I integrated it into Josh Long's x-auth-security project. If you have a Boot-powered project, you should be able to use the same steps.

1. Add swagger-springmvc dependency to your project.


Note: on my client's project, we had to exclude "org.slf4j:slf4j-log4j12" and add "jackson-module-scala_2.10:2.3.1" as a dependency. I did not need to do either of these in this project.

2. Add a SwaggerConfig class to configure Swagger.

The swagger-springmvc documentation has an example of this with a bit more XML.

package example.config;

import com.mangofactory.swagger.configuration.JacksonScalaSupport;
import com.mangofactory.swagger.configuration.SpringSwaggerConfig;
import com.mangofactory.swagger.configuration.SpringSwaggerModelConfig;
import com.mangofactory.swagger.configuration.SwaggerGlobalSettings;
import com.mangofactory.swagger.core.DefaultSwaggerPathProvider;
import com.mangofactory.swagger.core.SwaggerApiResourceListing;
import com.mangofactory.swagger.core.SwaggerPathProvider;
import com.mangofactory.swagger.scanners.ApiListingReferenceScanner;
import com.wordnik.swagger.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

@ComponentScan(basePackages = "com.mangofactory.swagger")
public class SwaggerConfig {

    public static final List<String> DEFAULT_INCLUDE_PATTERNS = Arrays.asList("/news/.*");
    public static final String SWAGGER_GROUP = "mobile-api";

    private String docsLocation;

    private SpringSwaggerConfig springSwaggerConfig;
    private SpringSwaggerModelConfig springSwaggerModelConfig;

     * Adds the jackson scala module to the MappingJackson2HttpMessageConverter registered with spring
     * Swagger core models are scala so we need to be able to convert to JSON
     * Also registers some custom serializers needed to transform swagger models to swagger-ui required json format
    public JacksonScalaSupport jacksonScalaSupport() {
        JacksonScalaSupport jacksonScalaSupport = new JacksonScalaSupport();
        //Set to false to disable
        return jacksonScalaSupport;

     * Global swagger settings
    public SwaggerGlobalSettings swaggerGlobalSettings() {
        SwaggerGlobalSettings swaggerGlobalSettings = new SwaggerGlobalSettings();
        return swaggerGlobalSettings;

     * API Info as it appears on the swagger-ui page
    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfo(
                "News API",
                "Mobile applications and beyond!",
                "Apache 2.0",
        return apiInfo;

     * Configure a SwaggerApiResourceListing for each swagger instance within your app. e.g. 1. private  2. external apis
     * Required to be a spring bean as spring will call the postConstruct method to bootstrap swagger scanning.
     * @return
    public SwaggerApiResourceListing swaggerApiResourceListing() {
        //The group name is important and should match the group set on ApiListingReferenceScanner
        //Note that swaggerCache() is by DefaultSwaggerController to serve the swagger json
        SwaggerApiResourceListing swaggerApiResourceListing = new SwaggerApiResourceListing(springSwaggerConfig.swaggerCache(), SWAGGER_GROUP);

        //Set the required swagger settings

        //Use a custom path provider or springSwaggerConfig.defaultSwaggerPathProvider()

        //Supply the API Info as it should appear on swagger-ui web page

        //Global authorization - see the swagger documentation

        //Every SwaggerApiResourceListing needs an ApiListingReferenceScanner to scan the spring request mappings
        return swaggerApiResourceListing;

     * The ApiListingReferenceScanner does most of the work.
     * Scans the appropriate spring RequestMappingHandlerMappings
     * Applies the correct absolute paths to the generated swagger resources
    public ApiListingReferenceScanner apiListingReferenceScanner() {
        ApiListingReferenceScanner apiListingReferenceScanner = new ApiListingReferenceScanner();

        //Picks up all of the registered spring RequestMappingHandlerMappings for scanning

        //Excludes any controllers with the supplied annotations


        //Path provider used to generate the appropriate uri's

        //Must match the swagger group set on the SwaggerApiResourceListing

        //Only include paths that match the supplied regular expressions

        return apiListingReferenceScanner;

     * Example of a custom path provider
    public ApiPathProvider apiPathProvider() {
        ApiPathProvider apiPathProvider = new ApiPathProvider(docsLocation);
        return apiPathProvider;

    private List<AuthorizationType> authorizationTypes() {
        ArrayList<AuthorizationType> authorizationTypes = new ArrayList<>();

        List<AuthorizationScope> authorizationScopeList = newArrayList();
        authorizationScopeList.add(new AuthorizationScope("global", "access all"));

        List<GrantType> grantTypes = newArrayList();

        LoginEndpoint loginEndpoint = new LoginEndpoint(apiPathProvider().getAppBasePath() + "/user/authenticate");
        grantTypes.add(new ImplicitGrant(loginEndpoint, "access_token"));

        return authorizationTypes;

    public SwaggerPathProvider relativeSwaggerPathProvider() {
        return new ApiRelativeSwaggerPathProvider();

    private class ApiRelativeSwaggerPathProvider extends DefaultSwaggerPathProvider {
        public String getAppBasePath() {
            return "/";

        public String getSwaggerDocumentationBasePath() {
            return "/api-docs";

The ApiPathProvider class referenced above is as follows:

package example.config;

import com.mangofactory.swagger.core.SwaggerPathProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.ServletContext;

public class ApiPathProvider implements SwaggerPathProvider {
    private SwaggerPathProvider defaultSwaggerPathProvider;
    private ServletContext servletContext;

    private String docsLocation;

    public ApiPathProvider(String docsLocation) {
        this.docsLocation = docsLocation;

    public String getApiResourcePrefix() {
        return defaultSwaggerPathProvider.getApiResourcePrefix();

    public String getAppBasePath() {
        return UriComponentsBuilder

    public String getSwaggerDocumentationBasePath() {
        return UriComponentsBuilder

    public String getRequestMappingEndpoint(String requestMappingPattern) {
        return defaultSwaggerPathProvider.getRequestMappingEndpoint(requestMappingPattern);

    public void setDefaultSwaggerPathProvider(SwaggerPathProvider defaultSwaggerPathProvider) {
        this.defaultSwaggerPathProvider = defaultSwaggerPathProvider;

In src/main/resources/application.properties, add an "app.docs" property. This will need to be changed as you move your application from local -> test -> staging -> production. Spring Boot's externalized configuration makes this fairly simple.


3. Verify Swagger produces JSON.

After completing the above steps, you should be able to see the JSON Swagger generates for your API. Open http://localhost:8080/api-docs in your browser or curl http://localhost:8080/api-docs.

    "apiVersion": "1",
    "swaggerVersion": "1.2",
    "apis": [
            "path": "http://localhost:8080/api-docs/mobile-api/example_NewsController",
            "description": "example.NewsController"
    "info": {
        "title": "News API",
        "description": "Mobile applications and beyond!",
        "termsOfServiceUrl": "https://helloreverb.com/terms/",
        "contact": "matt@raibledesigns.com",
        "license": "Apache 2.0",
        "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html"

4. Copy Swagger UI into your project.

Swagger UI is a good-looking JavaScript client for Swagger's JSON. I integrated it using the following steps:

git clone https://github.com/wordnik/swagger-ui
cp -r swagger-ui/dist ~/dev/x-auth-security/src/main/resources/public/docs

I modified docs/index.html, deleting its header (<div id='header'>) element, as well as made its url dynamic.

$(function () {
  var apiUrl = window.location.protocol + "//" + window.location.host;
  if (window.location.pathname.indexOf('/api') > 0) {
    apiUrl += window.location.pathname.substring(0, window.location.pathname.indexOf('/api'))
  apiUrl += "/api-docs";
  log('API URL: ' + apiUrl);
  window.swaggerUi = new SwaggerUi({
    url: apiUrl,
    dom_id: "swagger-ui-container",

After making these changes, I was able to open fire up the app with "mvn spring-boot:run" and view http://localhost:8080/docs/index.html in my browser.

5. Annotate your API.

There are two services in x-auth-security: one for authentication and one for news. To provide more information to the "news" service's documentation, add @Api and @ApiOperation annotations. These annotations aren't necessary to get a service to show up in Swagger UI, but if you don't specify the @Api("user"), you'll end up with an ugly-looking class name instead (e.g. example_xauth_UserXAuthTokenController).

@Api(value = "news", description = "News API")
class NewsController {

    Map<Long, NewsEntry> entries = new ConcurrentHashMap<Long, NewsEntry>();

    @RequestMapping(value = "/news", method = RequestMethod.GET)
    @ApiOperation(value = "Get News", notes = "Returns news items")
    Collection<NewsEntry> entries() {
        return this.entries.values();

    @RequestMapping(value = "/news/{id}", method = RequestMethod.DELETE)
    @ApiOperation(value = "Delete News item", notes = "Deletes news item by id")
    NewsEntry remove(@PathVariable Long id) {
        return this.entries.remove(id);

    @RequestMapping(value = "/news/{id}", method = RequestMethod.GET)
    @ApiOperation(value = "Get a news item", notes = "Returns a news item")
    NewsEntry entry(@PathVariable Long id) {
        return this.entries.get(id);

    @RequestMapping(value = "/news/{id}", method = RequestMethod.POST)
    @ApiOperation(value = "Update News", notes = "Updates a news item")
    NewsEntry update(@RequestBody NewsEntry news) {
        this.entries.put(news.getId(), news);
        return news;

You might notice the screenshot above only shows news. This is because SwaggerConfig.DEFAULT_INCLUDE_PATTERNS only specifies news. The following will include all APIs.

public static final List<String> DEFAULT_INCLUDE_PATTERNS = Arrays.asList("/.*");

After adding these annotations and modifying SwaggerConfig, you should see all available services.

In swagger-springmvc 0.8.x, the ability to use @ApiModel and @ApiModelProperty annotations was added. This means you can annotate NewsEntry to specify which fields are required.

@ApiModel("News Entry")
public static class NewsEntry {
    @ApiModelProperty(value = "the id of the item", required = true)
    private long id;
    @ApiModelProperty(value = "content", required = true)
    private String content;

    // getters and setters

This results in the model's documentation showing up in Swagger UI. If "required" isn't specified, a property shows up as optional.

Parting Thoughts

The QA Engineers and 3rd Party iOS Developers have been very pleased with our API documentation. I believe this is largely due to Swagger and its nice-looking UI. The Swagger UI also provides an interface to test the endpoints by entering parameters (or JSON) into HTML forms and clicking buttons. This could benefit those QA folks that prefer using Selenium to test HTML (vs. raw REST endpoints).

I've been quite pleased with swagger-springmvc, so kudos to its developers. They've been very responsive in fixing issues I've reported. The only thing I'd like is support for recognizing JSR303 annotations (e.g. @NotNull) as required fields.

To see everything running locally, checkout my modified x-auth-security project on GitHub and the associated commits for this article.

The Integration Zone is brought to you in partnership with 3scale. Learn how to deploy an NGINX API gateway on Heroku.

documentation,integration,swagger,spring api

Published at DZone with permission of Matt Raible , DZone MVB .

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}