Java REST API Documentation with Swagger2

Introduction

In this article, we'll dive into the Swagger framework. We'll use Swagger2 to design, build, and document a Spring Boot RESTful API and Swagger UI to observe our endpoints and test them.

What is Swagger?

Swagger is the most widely used tool for building APIs compliant to the OpenAPI Specification (OAS).

Swagger itself is a set of open-source tools built around the OAS that can help you design, build, document, and generate the REST API documents for RESTful web services.

The most prominent Swagger tools are:

  • Swagger Editor – browser-based editor where you can write OpenAPI specs
  • Swagger UI – renders OpenAPI specs as interactive API documentation
  • Swagger Codegen – generates server stubs and client libraries from an OpenAPI spec

Swagger2 is an extension of Swagger into new technologies and protocols beyond HTTP.

Building an Application

Integrating Swagger2 into a Spring Boot application is quite fast and easy with the help of some tools we already use day-in and day-out.

The simplest way to start with a skeleton Spring Boot project, as always, is using Spring Initializr.

Select your preferred version of Spring Boot and generate it as a Maven project and you're all set!

To enable Swagger2 itself, you'll need to add a couple of dependencies to your pom.xml file:

<dependency>  
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>${version}</version>
</dependency>  

With our project fully set-up and our dependencies in check, we can go ahead and create a simple REST endpoint which we'll expose in the documentation later on:

@RestController
@RequestMapping("/v1/hello")
public class HelloResource {

    @GetMapping
    public String hello() {
        return "Hello World";
    }

    @PostMapping("/post")
    public String helloPost(@RequestBody String hello) {
        return hello;
    }

    @PutMapping("/put")
    public String helloPut(@RequestBody String hello) {
        return hello;
    }
}

After this, let's go ahead and create one more REST endpoint - UserResource:

@RestController
@RequestMapping("/v1/user")
public class UserResource {

@GetMapping
public List<User> getUsers() {  
    return Arrays.asList(
        new User("John", 3000),
        new User("Kevin", 2000)
    );
}

@GetMapping("/{userName}")
public User getUser(@PathVariable("userName") String userName) {  
    return new User(userName, 2000);
}

Both of these classes rely on the User model:

private class User {

    private String userName;
    private Integer salary;

    // constructor, getters and setters
}

Enabling Swagger2

Now is about the time to enable Swagger2 in our application by defining a configuration class for it.

The configuration class needs to be annotated with @Configuration - the standard Spring annotation, and @EnableSwagger2 annotations to enable the framework for your Spring Boot application.

The order of these annotations isn't important:

@EnableSwagger2
@Configuration
public class Swagger2Config {

    @Bean
    public Docket productApi() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.demo.resource"))
            .paths(regex("/v1.*"))
            .build();
    }
}

We'll define a Bean named Docket in the configuration class for this purpose.

Docket is a builder which is intended to be the primary interface into the swagger-springmvc framework. It provides sensible defaults and convenience methods for configuration.

After the Docket bean is defined, calling its select() method returns an instance of ApiSelectorBuilder, which provides control over the endpoints exposed by Swagger.

We can define a base package for our REST API classes as well if we wish to, using RequestHandlerSelectors.basePackage(). It will scan the base package and create APIs for all of the classes within it.

On the other hand, we can use RequestHandlerSelectors.any() to generate documentation for all packages.

In our case, it's the com.demo.resource package, where we defined the HelloResource and UserResource classes.

The paths() method further defines for which paths in our APIs do we want to create documentation for. All of our endpoints have "/v1", so in our case it includes all of the endpoints. However, this may not always be the case.

If you'd wish to include all endpoints - you can easily do so by using PathSelectors.any().

Swagger UI

Let's use Swagger UI to observe all of our REST endpoints that Swagger created.

To utilize Swagger UI, we need to add a dependency for it to our pom.xml file:

<dependency>  
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>${version}</version>
</dependency>  

Now, navigate to localhost:8080/swagger-ui.html. This is the URL where we can observe all rest endpoints which Swagger created:

As you can see, both of our endpoints are here - hello-resource and user-resource, with their respective methods inside. The method names are defined on the right, as you can see.

We can use this UI to test out our endpoints:

  • Click on HelloResource and expand GET/v1/hello
  • Click the rest call Try it out button

We'll be greeted with the Response Body "Hello World" and Response Code 200 which means that it's working as intended.

Same as for the GET/v1/user from the class UserResource:

We'll be greeted with the information relevant to the user we created before.

Customizing Swagger2

Sometimes, companies and teams need to customize Swagger2's behavior, adding custom messages and operations to tailor the use of the framework to their own needs.

To do this, we need to override the meta information of the framework with ApiInfo.

The constructor of ApiInfo expects:

  • String title
  • String description
  • String version
  • String termsOfServiceUrl
  • new Contact(contactName, "", "")
  • String license
  • String licenseUrl

If you don't want to define any of these, you can just input null and that field will not be shown on the UI:

@EnableSwagger2
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket productApi() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.demo.resource"))
            .paths(regex("/v1.*"))
            .build()
            .apiInfo(metaInfo());
    }

    private ApiInfo metaInfo() {

        ApiInfo apiInfo = new ApiInfo(
            "Spring Boot Swagger2 Example API",
            null,
            "1.0",
            "Terms of Service",
            new Contact("Your Name or Team", null,
                null),
            "Apache License Version 2.0",
            "https://www.apache.org/licenses/"
        );

        return apiInfo;
    }
}

We can override method names with annotations.

The @ApiOperation annotation allows us to override the endpoint and its response type. Swagger2 also allows overriding the default response messages of HTTP methods.

You can use the @ApiResponse annotation to document other responses, in addition to the regular HTTP 200 OK:

@ApiOperation(value = "Returns Hello World", description = "shows hello world")
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "The request has succeeded or (your message)"),
        @ApiResponse(code = 401, message = "The request requires user authentication or (your message)"),
        @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden or (your message)"),
        @ApiResponse(code = 404, message = "The server has not found anything matching the Request-URI or (your message)")

Let's take a look at the UI:

Upon expanding hello-resource we can see that the right side of the documentation got updated. Also, the response messages updated with code that we provided and return type from the @Api annotation on class level.

Model Properties

Swagger2 provides us with a set of annotations to manipulate models with a lot of control:

  • @ApiModel - Allows us to manipulate meta data of a model
  • @ApiModelProperty - Allows us control over Swagger-specific definitions and operations (allowed values, notes, filtering)

We'll need to update our UserResource controller with the @Api annotation on the class level.

In Swagger2, this annotation is used to apply definitions to all operations defined under it, unlike its usage in previous versions, where it declared resources:

@RestController
@RequestMapping("/v1/user")
@Api(value = "User Resource REST Endpoint", description = "Shows the user info")
public class UserResource {

    @GetMapping
    public List<User> getUsers() {

        return Arrays.asList(
            new User("John", 2000),
            new User("Kevin", 1000)
        );
    }

    @GetMapping("/{userName}")
    public User getUser(@PathVariable("userName") String userName) {
        return new User(userName, 1000);
    }

After updating the API, let's update the model too:

@ApiModel
private class User {

    @ApiModelProperty(notes = "name of the user")
    private String userName;

    @ApiModelProperty(notes = "salary of the user")
    private Integer salary;

    @ApiModelProperty(allowableValues = "active, inactive, banned")
    private String status;

    // constructor, getters and setters
}

There's a wide range of things you can define using @ApiModelProperty. For more information and a list of methods, visit the official documentation.

Expanding GET/v1/user then clicking on the Model property, we can notice the descriptions on each field.

"Example Value" shows just default values.

Conclusion

Each day, companies and individuals are starting to use Swagger as their tool of choice for exposing REST APIs to third parties.

Utilizing Swagger's tools, you can generate code based on the documentation of an API, as well as create beautiful, interactive documentation. This both saves time and effort and offers a standard for people to work with.

Author image
About Vuk Skobalj