使用OpenAPI 3.0记录Spring REST API

Documenting a Spring REST API Using OpenAPI 3.0

1.概述

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

进一步阅读:

使用Swagger生成Spring Boot REST Client

使用Spring REST API设置Swagger 2

Spring Cloud合约简介

2.设置springdoc-openapi

为了让springdoc-openapi自动为我们的API生成OpenAPI 3规范文档,我们只需将springdoc-openapi-ui依赖项添加到我们的pom.xml中:

1
2
3
4
5
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.2.32</version>
</dependency>

然后,当我们运行应用程序时,默认情况下,OpenAPI描述将在路径/ v3 / api-docs中可用-例如:

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

要使用定制路径,我们可以在application.properties文件中指出:

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

现在,我们可以在以下位置访问文档:

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

默认情况下,OpenAPI定义为JSON格式。 对于yaml格式,我们可以在以下位置获取定义:

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

3.使用Swagger UI设置springdoc-openapi

除了自己生成OpenAPI 3规范外,我们还可以将springdoc-openapi与Swagger UI集成在一起,以便我们可以与我们的API规范进行交互并行使端点。

3.1。 Maven依赖

使用Swagger UI设置springdoc-openapi所要做的就是将依赖项springdoc-openapi-ui添加到项目的pom.xml中:

1
2
3
4
5
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.2.32</version>
</dependency>

现在,我们可以在以下位置访问API文档:

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

3.2。 支持swagger-ui属性

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

例如,让我们自定义API文档的路径。 我们可以通过修改application.properties使其包括:

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

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

再举一个例子,要按API方法的HTTP方法顺序对它们进行排序,我们可以添加:

1
springdoc.swagger-ui.operationsSorter=method

3.3。 样本API
<

假设我们的应用程序具有一个用于管理图书的控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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;
    }
}

然后,当我们运行应用程序时,可以在以下位置查看文档:

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

Swagger UI

让我们深入到/ api / book端点,并查看其请求和响应的详细信息:

Swagger UI API Details

Swagger UI API Details

4.将springdoc-openapi与Spring WebFlux集成

通过添加springdoc-openapi-webflux-ui,我们可以将Springdoc-openapi和Swagger UI集成到Spring WebFlux项目中

1
2
3
4
5
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webflux-ui</artifactId>
    <version>1.2.32</version>
</dependency>

而且,像以前一样,可以在以下位置访问该文档:

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

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

5.公开分页信息

Spring Data JPA与Spring MVC无缝集成。 此类集成的一个示例是Pageable支持:

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

刚开始,我们可能希望SpringDoc在生成的文档中添加页面,大小和对查询参数进行排序。 但是,默认情况下,SpringDoc不满足此期望。 为了解锁此功能,我们应该添加springdoc-openapi-data-rest

1
2
3
4
5
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-data-rest</artifactId>
    <version>1.2.32</version>
</dependency>

现在,它将预期的查询参数添加到文档中:

Book Filter API with Query Parameters Added

6.使用springdoc-openapi Maven插件

springdoc-openapi库提供了一个Maven插件springdoc-openapi-maven-plugin

springdoc-openapi-maven-plugin插件与spring-boot-maven插件一起使用。 Maven在集成测试阶段运行openapi插件。

让我们看看如何在pom.xml中配置插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<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>

另外,我们可以配置插件以使用自定义值:

1
2
3
4
5
6
7
8
9
10
<plugin>
    <executions>
        .........
    </executions>
    <configuration>
        <apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl>
        <outputFileName>openapi.json</outputFileName>
        <outputDir>${project.build.directory}</outputDir>
    </configuration>
</plugin>

让我们仔细看看我们可以为插件配置的参数:

  • apiDocsUrl –可以使用JSON格式访问文档的URL,默认为http:// localhost:8080 / v3 / api-docs

  • outputFileName –存储定义的文件的名称,默认为openapi.json

  • outputDir –文档存储目录的绝对路径–默认情况下,$ {project.build.directory}

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

    当我们的模型包含JSR-303 bean验证批注(例如@ NotNull,@ NotBlank,@ Size,@ Min和@Max)时,springdoc-openapi库将使用它们来生成相应约束的其他模式文档。

    让我们来看一个使用Book Bean的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Book {

        private long id;

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

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

    }

    现在,为Book bean生成的文档提供了更多信息:

    Book Schema After Adding Bean Validation

    Book Schema After Adding Bean Validation

    8.使用@ControllerAdvice和@ResponseStatus生成文档

    在@RestControllerAdvice类中的方法上使用@ResponseStatus将自动生成响应代码的文档。 在此@RestControllerAdvice类中,这两种方法都用@ResponseStatus进行注释:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @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);
        }
    }

    结果,我们现在可以看到响应代码400和404的文档:

    Documentation for @ControllerAdvice and @ResponseStatus

    Documentation for @ControllerAdvice and @ResponseStatus

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

    接下来,让我们看看如何使用几个特定于OpenAPI的注释向我们的API添加一些描述。

    为此,我们将使用@Operation和@ApiResponses注释控制器的/ api / book / {id}端点:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @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());
    }

    效果如下:

     width=

    如我们所见,添加到@Operation的文本位于API操作级别。 同样,添加到@ApiResponse容器批注中各种@ApiResponse元素的描述在此处也可见,这为我们的API响应增加了含义。

    显然,我们没有得到以上响应400和404的任何模式。 因为我们为它们定义了一个空的@Content,所以仅显示它们的描述。

    10. Kotlin支持

    由于Spring Boot 2.x对Kotlin具有一流的支持,因此SpringDoc为Boot 2.x应用程序提供了开箱即用的JVM语言。

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

    初始设置后,我们将添加一个数据类和一个控制器。 我们将它们添加到Boot App的子包中,以便在运行时将FooController与早期的BookController一起使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    @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
    }

    现在,当我们点击API文档URL时,我们还将看到Foo API:

     width=

    为了增强对Kotlin类型的支持,我们可以添加以下依赖:

    1
    2
    3
    4
    5
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-kotlin</artifactId
        <version>1.3.9</version>
    </dependency>

    在那之后,我们的Foo模式将看起来更有用。 与添加JSR-303 Bean验证时类似:

     width=

    11.结论

    在本文中,我们学习了在项目中设置springdoc-openapi的过程。 然后,我们看到了如何将Springdoc-openapi与Swagger UI集成在一起。 我们还看到了如何使用Spring Webflux项目来做到这一点。

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

    然后,我们学习了如何使用一些特定于OpenAPI的注释向我们的API添加描述。 最后,我们窥视了OpenAPI对Kotlin的支持。

    springdoc-openapi根据OpenAPI 3规范生成API文档。 此外,它还为我们处理Swagger UI配置,从而使API文档生成成为一个相当简单的任务。

    与往常一样,该代码可在GitHub上获得。