使用OpenAPI 3.0记录Spring REST API

2023/05/12

1. 概述

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

2. 设置springdoc-openapi

要让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>

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

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

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

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

现在,我们将能够在以下位置访问文档:

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

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

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

3. 与Swagger UI集成

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

springdoc-openapi依赖项已经包含Swagger UI,所以我们都在这里设置。

我们可以简单地在以下位置访问API文档:

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

3.1 支持swagger-ui属性

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

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

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

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

作为另一个例子,要按照HTTP方法的顺序对API路径进行排序,我们可以添加:

springdoc.swagger-ui.operationsSorter=method

3.2 示例API

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

@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;
    }
}

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

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


![](/assets/images/2023/springboot/springrestopenapidocumentation01.png)

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

![](/assets/images/2023/springboot/springrestopenapidocumentation02.png)

## 4. 将springdoc-openapi与Spring WebFlux集成

我们可以通过添加[springdoc-openapi-webflux-ui](https://search.maven.org/search?q=a:springdoc-openapi-webflux-ui)将springdoc-openapi和Swagger UI集成到Spring WebFlux项目中:

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

和以前一样,可以在以下位置访问文档:

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


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

## 5. 公开分页信息

Spring Data JPA与Spring MVC无缝集成,这种集成的一个例子是Pageable支持:

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

自springdoc-openapi v1.6.0以来,对Pageable的支持是开箱即用的,Page、size和sort查询参数被添加到生成的文档中:

6. 使用springdoc-openapi Maven插件

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

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

让我们看看如何在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>

我们还可以将插件配置为使用自定义值:

<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的例子:

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生成的文档提供了更多的信息:

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

在@RestControllerAdvice类中的方法上使用@ResponseStatus将自动生成响应代码的文档,在以下的@RestControllerAdvice类中,这两个方法使用@ResponseStatus注解进行了标注:

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(ConversionFailedException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<String> handleConversion(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的文档:

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

接下来让我们看看如何使用一些特定于OpenAPI的注解为我们的API添加一些描述。

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

@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(BookNotFoundException::new);
}

效果如下:

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

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

10. Kotlin支持

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

为了看到实际效果,我们将使用Kotlin创建一个简单的Foo API。

初始设置后,我们将添加一个数据类和一个控制器,我们将它们添加到我们的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<Foo> = 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<Foo> = fooList
}

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

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

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

之后,我们的Foo模式看起来会提供更多信息,就像我们添加JSR-303 Bean Validation时一样:

11. 总结

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

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

我们还学习了如何使用一些特定于OpenAPI的注解向我们的API添加描述。最后,我们演示了OpenAPI对Kotlin的支持。

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

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章