Spring Boot Swagger documentation using OpenAPI

Spring Boot Swagger documentation using OpenAPI

Rich API documentation is a vital element of any successful project, especially if it has to be integrated by third parties. Unfortunately, Spring Boot does not have an out-of-the-box solution for Swagger documentation. So we must use a third-party library (Springdoc-openapi) for that purpose. In this article, we cover how to add Spring Boot Swagger documentation using the OpenAPI library.

Swagger versus Spring REST Docs

Generally, there are two approaches to documenting APIs in Spring Boot apps. Swagger and Spring REST Docs.

Swagger is widely used and provides an easy-to-interact interface to call APIs to experiment with them. However, it creates coupling in the codebase as you need to use a specific set of documentation annotations. In other words, the code is tied to a library, and swapping it will not be easy. Additionally, updating APIs may cause inconsistencies if one forgets to update the Swagger documentation. Hence, the code might get messy and difficult to maintain.

On the other hand, Spring REST Docs does not have the coupling issue at the code level since there is no need for annotations.
Test cases generate the API documentation. That means developers out to write clean and comprehensive tests at the controller level. Overall, it enforces good practices. The downsides of this approach are that documentation generation is more time-consuming, and the generated documentation doesn’t provide a way to interact with API with a single click or two.

While in theory, the Spring REST Docs approach seems superior, it does not necessarily work the best in all projects, especially in fast pacing environments where a short feedback cycle by clients is required.

Therefore, it is easier to start with Swagger and then switch to Spring REST Docs if the documentation maintenance becomes complex.

Currently, the best tool available to generate Swagger doc is the Springdoc-openapi library. In the next section, we discuss the reasoning behind it.

Why Springdoc OpenAPI

If you have worked with Spring Boot long enough, you may remember the SpringFox Swagger2 project, which was popular in earlier versions of Spring Boot.

Unfortunately, that project is currently unmaintained. It is no longer possible to use it in any Spring Boot version after 2.5, let alone 3.X. Hence we need to look for an alternative. The closest match in terms of active development and compatibility is the Springdoc-openapi.

Springdoc OpenAPI is not a drop and replacement to SpringFox Swagger2 as it has its own set of annotations, but replacing them is not complex since they are very similar with minor differences.

Add Springdoc OpenAPI to a Spring Boot project

Let’s begin by adding Springdoc OpenAPI to a project (only for Spring Boot 3),

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.5.0</version>
</dependency>

If you use Spring Boot 2.X and 1.X, you need to use a different dependency as follows,

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.8.0</version>
</dependency>

After that, your Swagger documentation should be available at the /swagger-ui/index.html path.

You can add an additional path by setting a property in the application.properties file as below,

springdoc.swagger-ui.path=/custom-url.html

Configuring Springdoc OpenAPI in code

The next step is to configure the library. Of course, this step is optional but highly recommended. We proceed by creating a config file called SwaggerConfiguration containing information about the nature of the API, maintainer contact info, and licensing as follows,

@Configuration
public class SwaggerConfiguration {

    @Bean
    public OpenAPI apiInfo() {
        return new OpenAPI().info(new Info().title("Test API documentation")
                .description("Documentation for Test weather API")
                .version("v1")
                .contact(getContactDetails())
                .license(getLicenseDetails()));
    }

    private Contact getContactDetails() {
        return new Contact().name("Contact Person").email("[email protected]").url("https://website.com");
    }

    private License getLicenseDetails() {
        return new License().name("License name").url("https://license-url.com");
    }
}

Add documentation to Rest APIs

Finally, we need to annotate the Rest APIs and add adequate documentation. For that, we assume to have a simple weather endpoint to document. Clients must pass latitude and longitude and optionally a flag to determine whether they would receive weather temperature in Fahrenheit.

The API code looks like this,

public Callable<ResponseEntity<CurrentWeatherCondition>> getCurrent(@RequestParam(value = "lat") String latitude, @RequestParam(value = "lon") String longitude,
    @RequestParam(value = "fahrenheit", required = false, defaultValue = "false") boolean fahrenheit, HttpServletRequest request) {
        // removed for brevity
}

For the above endpoint, we can add API documentation using OpenAPI library annotation as follows,

@Operation(summary = "Get current weather condition based on latitude and longitude",
        parameters = {
            @Parameter(name = "lat", description = "Latitude of a location", required = true, example = "52.5200"),
            @Parameter(name = "lon", description = "Longitude of a location", example = "13.4050", required = true),
            @Parameter(name = "fahrenheit", description = "Return weather temperatures in Fahrenheit instead of Celsius", example = "false")
        }, tags = "Get weather by latitude, longitude")
    @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieve weather condition"), @ApiResponse(responseCode = "400", description = "Failed to get weather condition") })
    @GetMapping(value = { "v1/weather/current", "/current" }, produces = "application/json")
    
    public Callable<ResponseEntity<CurrentWeatherCondition>> getCurrent(@RequestParam(value = "lat") String latitude, @RequestParam(value = "lon") String longitude,
        @RequestParam(value = "fahrenheit", required = false, defaultValue = "false") boolean fahrenheit, HttpServletRequest request) {
        // removed for brevity
    }

The backbone of the documentation is the @Operation annotation. It has a summary field to explain the function of the API, parameters accompanied by description and examples to describe each, and finally, tags to categorize or group APIs together.

The @ApiResponse annotation is necessary for explaining response codes generated by the API.

Conclusion

In this article, we explored how to add Spring Boot Swagger documentation using the OpenAPI started by highlighting the differences between Swagger and Spring REST Docs and explaining each approach’s pros and cons. Then we covered integrating the springdoc-openapi into a Spring Boot project to enable Swagger documentation generation. Finally, we provided an example of REST API annotation.

Two code examples are available for this article on GitHub, Java, and Kotlin:

Inline/featured images credits