Documenting a Spring REST API Using OpenAPI 3.0 – 使用OpenAPI 3.0编写Spring REST API的文档

最后修改: 2019年 11月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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.

文档是构建REST API的一个重要部分。在本教程中,我们将看看SpringDoc–一个简化了Spring Boot 1.x和2.x应用程序基于OpenAPI 3规范的API文档生成和维护的工具。

2. Setting up springdoc-openapi

2.设置springdoc-openapi

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

为了让springdoc-openapi自动为我们的API生成OpenAPI 3规范文档,我们只需将springdoc-openapi-ui依赖关系加入我们的pom.xml

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

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

然后当我们运行我们的应用程序时,OpenAPI描述将在路径/v3/api-docs中默认可用。

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

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

要使用一个自定义的路径,我们可以在application.properties文件中说明。

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:

OpenAPI的定义默认为JSON格式。对于yaml格式,我们可以在以下网站获得定义。

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

3. Integration with Swagger UI

3.与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.

除了生成OpenAPI 3规范本身,我们还可以将springdoc-openapi与Swagger UI集成,这样我们就可以与我们的API规范进行交互,并行使端点。

The springdoc-openapi dependency already includes Swagger UI, so we’re all set here.

springdoc-openapi依赖性已经包括了Swagger UI,所以我们在这里都准备好了。

We can simply access the API documentation at:

我们可以简单地访问API文档:。

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

3.1. Support for swagger-ui Properties

3.1.对swagger-ui属性的支持

Springdoc-openapi also supports swagger-ui properties. These can be used as Spring Boot properties, with the prefix springdoc.swagger-ui.

Springdoc-openapi还支持swagger-ui属性。这些可以作为Spring Boot属性使用,其前缀为springdoc.swagger-ui

For example, let’s customize the path of our API documentation. We can do this by modifying our application.properties to include:

例如,让我们自定义我们的API文档的路径。我们可以通过修改我们的application.properties来做到这一点,包括。

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

So now our API documentation will be available at http://localhost:8080/swagger-ui-custom.html.

因此,现在我们的API文档将在http://localhost:8080/swagger-ui-custom.html上提供。

As another example, to sort the API paths in order of their HTTP methods, we can add:

再比如,为了按照HTTP方法的顺序对API路径进行排序,我们可以添加。

springdoc.swagger-ui.operationsSorter=method

3.2. Sample API

3.2.示例API

Suppose our application has a controller for managing Books:

假设我们的应用程序有一个控制器来管理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

Swagger UI

Let’s drill down to the /api/book endpoint and see the details for its request and response:
Swagger UI API Details

让我们深入到 /api/book 端点,看看其请求和响应的细节:
Swagger UI API Details

4. Integrating springdoc-openapi With Spring WebFlux

4.将springdoc-openapi与Spring WebFlux相结合

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

我们可以通过添加springdoc-openapi-webflux-ui在Spring WebFlux项目中集成springdoc-openapi和Swagger UI。

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

As before, the docs will be accessible at:

和以前一样,这些文件可以在以下网站上查阅。

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

In order to customize the path, we could again add the springdoc.swagger-ui.path property in our application.properties.

为了自定义路径,我们可以再次在我们的application.properties中添加springdoc.swagger-ui.path属性。

5. Exposing Pagination Information

5.暴露分页信息

Spring Data JPA integrates with Spring MVC quite seamlessly. One example of such integration is Pageable support:

Spring Data JPA与Spring MVC进行了相当无缝的集成。这种整合的一个例子是Pageable支持。

@GetMapping("/filter")
public Page<Book> filterBooks(@ParameterObject Pageable pageable) {
     return repository.getBooks(pageable);
}

The support for Pageable is available out-0f-the box since springdoc-openapi v1.6.0 . Page, size, and sort query parameters get added to the generated documentation.:

从springdoc-openapi v1.6.0开始,对Pageable的支持是开箱即用的。Pagesizesort查询参数被添加到生成的文档中。

Pageable

6. Using springdoc-openapi Maven Plugin

6.使用springdoc-openapi Maven插件

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

springdoc-openapi库提供了一个Maven插件springdoc-openapi-maven-plugin,用于生成jsonyaml格式的OpenAPI描述。

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

springdoc-openapi-maven-plugin插件与spring-boot-maven插件协同工作。Maven在集成测试阶段运行openapiplugin。

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

让我们看看如何在我们的pom.xml中配置该插件。

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.3.3.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>

We can also 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}

7. Automatic Document Generation Using JSR-303 Bean Validation

7.使用JSR-303 Bean验证的自动文档生成

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.

当我们的模型包括JSR-303Bean验证注解时,例如@NotNull, @NotBlank, @Size, @Min, 和@Max,springdoc-openapi库使用它们来为相应的约束生成额外的模式文档。

Let’s see an example using our Book bean:

让我们看一个使用我们的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:
Book Schema After Adding Bean Validation

现在,为Book bean生成的文档内容更丰富了:
Book Schema After Adding Bean Validation

8. Generate Documentation Using @ControllerAdvice and @ResponseStatus

8.使用@ControllerAdvice@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类中的方法上使用@ResponseStatus将自动生成响应代码的文档。在这个@RestControllerAdvice类中,两个方法被注解为@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);
    }
}

As a result, we can now see the documentation for the response codes 400 and 404:
Documentation for @ControllerAdvice and @ResponseStatus

因此,我们现在可以看到响应代码400和404的文档:
@ControllerAdvice和@ResponseStatus的文档

9. Generate Documentation Using @Operation and @ApiResponses

9.使用@Operation@ApiResponses生成文档

Next let’s see how we can add some description to our API using a couple of OpenAPI-specific annotations.

接下来让我们看看如何使用几个OpenAPI专用注释为我们的API添加一些描述。

In order to do that, we’ll annotate our controller’s /api/book/{id} endpoint with @Operation and @ApiResponses:

为了做到这一点,我们将在控制器的/api/book/{id}注解@Operation@ApiResponses端点。

@Operation(summary = "Get a book by its id")
@ApiResponses(value = { 
  @ApiResponse(responseCode = "200", description = "Found the book", 
    content = { @Content(mediaType = "application/json", 
      schema = @Schema(implementation = Book.class)) }),
  @ApiResponse(responseCode = "400", description = "Invalid id supplied", 
    content = @Content), 
  @ApiResponse(responseCode = "404", description = "Book not found", 
    content = @Content) })
@GetMapping("/{id}")
public Book findById(@Parameter(description = "id of book to be searched") 
  @PathVariable long id) {
    return repository.findById(id).orElseThrow(() -> new BookNotFoundException());
}

Here’s the effect:

效果是这样的。

BooksGetByID

As we can see, the text we added to @Operation is placed at the API operation level. Similarly, the description added to various @ApiResponse elements in the @ApiResponses container annotation is also visible here, adding meaning to our API responses.

我们可以看到,我们添加到@Operation的文本被放置在API操作层面。同样,添加到@ApiResponse容器注解中的各种@ApiResponses元素的描述在这里也是可见的,为我们的API响应增加了意义。

Evidently, we do not get any schema for the responses 400 and 404 above. As we defined an empty @Content for them, only their descriptions are displayed.

很明显,我们没有得到上述400和404响应的任何模式。由于我们为它们定义了一个空的@Content,只有它们的描述被显示出来。

10. Kotlin Support

10.Kotlin支持

Since Spring Boot 2.x has first-class support for Kotlin, SpringDoc supports this JVM language out of the box for Boot 2.x applications.

由于Spring Boot 2.x对Kotlin有一流的支持,SpringDoc对Boot 2.x应用程序支持这种JVM语言,开箱即用。

To see this in action, we’ll create a simple Foo API in Kotlin.

为了看到这一点,我们将在Kotlin中创建一个简单的Foo API。

After the initial setup, we’ll add a data class and a controller. We’ll add them in a sub-package of our Boot App so that when it’s run, it picks our FooController up along with the earlier BookController:

初始设置之后,我们将添加一个数据类和一个控制器。我们将把它们添加到Boot App的一个子包中,这样当它运行时,就会把我们的FooController和先前的BookController一起拿过来。

@Entity
data class Foo(
    @Id
    val id: Long = 0,
    
    @NotBlank
    @Size(min = 0, max = 50)
    val name: String = ""
)

@RestController
@RequestMapping("/")
class FooController() {
    val fooList: List = listOf(Foo(1, "one"), Foo(2, "two"))

    @Operation(summary = "Get all foos")
    @ApiResponses(value = [
	ApiResponse(responseCode = "200", description = "Found Foos", content = [
            (Content(mediaType = "application/json", array = (
                ArraySchema(schema = Schema(implementation = Foo::class)))))]),
	ApiResponse(responseCode = "400", description = "Bad request", content = [Content()]),
	ApiResponse(responseCode = "404", description = "Did not find any Foos", content = [Content()])]
    )
    @GetMapping("/foo")
    fun getAllFoos(): List = fooList
}

Now when we hit our API documentation URL, we’ll see the Foo API as well:

现在当我们点击我们的API文档URL时,我们也会看到Foo API。

To enhance the support of Kotlin types, we can add this dependency:

为了加强对Kotlin类型的支持,我们可以添加这个依赖项。

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-kotlin</artifactId
    <version>1.6.4</version>
</dependency>

After that, our Foo schema will look more informative, as it did when we added JSR-303 Bean Validation:

之后,我们的Foo模式将看起来更有信息量,就像我们添加JSR-303 Bean验证时那样。

FooSchema

11. Conclusion

11.结论

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.

在这篇文章中,我们学习了如何在我们的项目中设置springdoc-openapi。然后我们看到了如何将springdoc-openapi与Swagger UI集成。我们还看到了如何在Spring Webflux项目中这样做。

Next we used the springdoc-openapi Maven Plugin to generate OpenAPI definitions for our APIs, and we saw how to expose paging and sorting information from Spring Data. After that, we looked at how springdoc-openapi generates documentation automatically using JSR 303 bean validation annotations and the @ResponseStatus annotations in @ControllerAdvice class.

接下来我们使用springdoc-openapi Maven插件为我们的API生成OpenAPI定义,我们看到了如何从Spring Data中公开分页和排序信息。之后,我们看了springdoc-openapi如何使用JSR 303 Bean验证注解和@ControllerAdvice类中的@ResponseStatus注解自动生成文档。

We also learned how to add a description to our API using a few OpenAPI-specific annotations. Finally, we took a peek at OpenAPI’s support of Kotlin.

我们还学习了如何使用一些OpenAPI特有的注解来为我们的API添加描述。最后,我们看了一下OpenAPI对Kotlin的支持。

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

springdoc-openapi按照OpenAPI 3规范生成API文档。此外,它还为我们处理Swagger用户界面的配置,使API文档的生成成为一项相当简单的任务。

As always, the code is available over on GitHub.

像往常一样,代码可在GitHub上获得