Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
REST Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

Documentation is an essential part of building REST APIs. In this tutorial, we'll take a look at SpringDoc — a tool that simplifies the generation and maintenance of API docs, based on the OpenAPI 3 specification, for Spring Boot 1.x and 2.x applications.

2. Setting up springdoc-openapi

To have springdoc-openapi automatically generate the OpenAPI 3 specification docs for our API, we simply add the springdoc-openapi-core dependency to our pom.xml:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-core</artifactId>
    <version>1.1.44</version>
</dependency>

Then, when we run our application, the docs will be available at the path /v3/api-docs by default — for example:

http://localhost:8080/v3/api-docs/

To use a custom path, we can indicate in the application.properties file:

springdoc.api-docs.path=/api-docs

Now, we'll be able to access the docs at:

http://localhost:8080/api-docs/

The OpenAPI definitions are in JSON format by default. For yaml format, we can obtain the definitions at:

http://localhost:8080/api-docs.yaml

3. Setting up springdoc-openapi with Swagger UI

Besides generating the OpenAPI 3 specification itself, we can integrate springdoc-openapi with Swagger UI so that we can interact with our API specification and exercise the endpoints.

3.1. Maven Dependency

All we have to do to set up springdoc-openapi with Swagger UI is to add the dependency springdoc-openapi-ui to the project's pom.xml:

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

We can now access the API documentation at:

http://localhost:8080/swagger-ui.html

We could customize the path by adding the property:

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

3.2. Sample API

Suppose our application has a controller for managing Books:

@RestController
@RequestMapping("/api/book")
public class BookController {

    @Autowired
    private BookRepository repository;

    @GetMapping("/{id}")
    public Book findById(@PathVariable long id) {
        return repository.findById(id)
            .orElseThrow(() -> new BookNotFoundException());
    }

    @GetMapping("/")
    public Collection<Book> findBooks() {
        return repository.getBooks();
    }

    @PutMapping("/{id}")
    @ResponseStatus(HttpStatus.OK)
    public Book updateBook(@PathVariable("id") final String id, @RequestBody final Book book) {
        return book;
    }
}

Then, when we run our application, we can view the documentation at:

http://localhost:8080/swagger-ui-custom.html

Let's drill down to the /api/book endpoint and see the details for its request and response:

4. Integrating springdoc-openapi with Spring WebFlux

We can integrate springdoc-openapi and Swagger UI in a Spring WebFlux project by adding springdoc-openapi-webflux-ui:

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

And, as before, the docs will be accessible at:

http://localhost:8080/swagger-ui.html

Here again, we could add the springdoc.swagger-ui.path property in the application.properties file to customize the path.

5. Using springdoc-openapi Maven Plugin

The springdoc-openapi library provides a Maven plugin springdoc-openapi-maven-plugin for generating OpenAPI descriptions in json and yaml formats.

The springdoc-openapi-maven-plugin plugin works with the spring-boot-maven plugin. Maven runs the openapi plugin during the integration-test phase.

Let's see how we can configure the plugin in our pom.xml:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.1.8.RELEASE</version>
    <executions>
        <execution>
            <id>pre-integration-test</id>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>post-integration-test</id>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-maven-plugin</artifactId>
    <version>0.2</version>
    <executions>
        <execution>
            <phase>integration-test</phase>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Also, we can configure the plugin to use custom values:

<plugin>
    <executions>
        .........
    </executions>
    <configuration> 
        <apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl> 
        <outputFileName>openapi.json</outputFileName> 
        <outputDir>${project.build.directory}</outputDir> 
    </configuration>
</plugin>

Let's take a closer look at the parameters that we can configure for the plugin:

  • apiDocsUrl – URL where the docs can be accessed in json format, with a default of http://localhost:8080/v3/api-docs
  • outputFileName – Name of the file where the definitions are stored, defaults to openapi.json
  • outputDir – Absolute path for the directory where the docs are stored – by default, ${project.build.directory}

6. Automatic Document Generation Using JSR-303 Bean Validation

When our model includes JSR-303 bean validation annotations, such as @NotNull, @NotBlank, @Size, @Min, and @Max, the springdoc-openapi library uses them to generate additional schema documentation for the corresponding constraints.

Let's see an example using our Book bean:

public class Book {

    private long id;

    @NotBlank
    @Size(min = 0, max = 20)
    private String title;

    @NotBlank
    @Size(min = 0, max = 30)
    private String author;

}

Now, the documentation generated for the Book bean is a little more informative:

7. Generate Documentation Using @ControllerAdvice and @ResponseStatus

Using @ResponseStatus on methods in a @RestControllerAdvice class will automatically generate documentation for the response codes. In this @RestControllerAdvice class, the two methods are annotated with @ResponseStatus:

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(ConversionFailedException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<String> handleConnversion(RuntimeException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }
    
    @ExceptionHandler(BookNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<String> handleBookNotFound(RuntimeException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

And, we'll now see the documentation for the response codes 400 and 404:

8. Conclusion

In this article, we learned to set up springdoc-openapi in our projects. Then, we saw how to integrate springdoc-openapi with the Swagger UI. We also saw how to do this with Spring Webflux projects.

Next, we used the springdoc-openapi Maven Plugin to generate OpenAPI definitions for our APIs. Finally, we looked at how springdoc-openapi generates documentation automatically using JSR 303 bean validation annotations and the @ResponseStatus annotations in @ControllerAdvice class.

The springdoc-openapi generates API documentation as per OpenAPI 3 specification. It handles the Swagger UI configuration for us, making API document generation a fairly simple task.

As always, the code is available over on GitHub.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
REST bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
newest oldest most voted
Notify of
ectomorph
Guest
ectomorph

Great stuff. I also read your springfox article. Out of the two, which do you favour?

Eric Martin
Member
Eric Martin

Hey ectomorph,

We’re happy you liked it 🙂

Springdoc supported OpenAPI 3 for a longer time than Springfox. Also, in my experience, Springdoc has better error code and validation handling capabilities. Because of these reasons, I prefer Springdoc.

Note that it’s only a personal opinion, nothing more.

Cheers,
Team

Matt Diamond
Guest
Matt Diamond

We looked at this question ourselves recently. Unfortunately Springfox seems to have fallen behind both Spring and OpenAPI releases. Unless/until it supports Spring 2.2 and OpenDoc 3, you are probably on safer ground using SpringDoc.

However, keep in mind that some things may require more annotations with SpringDoc. Here’s one that bit us: https://github.com/swagger-api/swagger-ui/issues/5089

Additional references:
* There are some useful comments on this Springfox issue about how to migrate to SpringDoc, and differences. https://github.com/springfox/springfox/issues/2932
* This is probably the issue to watch if you want to hear if/when Springfox makes progress towards a new release:: https://github.com/springfox/springfox/issues/3070

Loredana Crusoveanu
Guest

Hey Matt,

Thanks for the additional info.

Cheers.

Guus
Guest
Guus

Can I use annotations like @ApiResponses here, and if so, how?

Eric Martin
Member
Eric Martin

Hey Guus,
Thanks for your question, we’ll add a section about that.
Cheers,
Team

Eim
Guest

Hi Eugen,

How to properly document API endpoints that use filter and pageable as request params?

For example:

@RequestMapping(method = RequestMethod.GET)
public Page getEmployees(@RequestParam(required = false) String filter,
@PageableDefault(sort = “name”) Pageable pageable) {
return convertToDtoPage(employeeService.findAll(pageable), this::convert, pageable);
}

Loredana Crusoveanu
Guest

Hey Eim,

We’ll look into it and update the article as soon as we can.

Comments are closed on this article!