1. 简介

Swagger 规范如今更常被称为 OpenAPI 规范。尽管 Smartbear 仍在维护一些工具,例如用于 Java 和 Kotlin 的 Swagger 注解,但在可能的情况下,应优先使用 OpenAPI 版本的工具和规范

本文将讨论在项目中使用 OpenAPI 规范的优势。通常有两种使用方式:一种是已有代码,需要生成 API 规范;另一种是已有规范,需要生成代码。

无论哪种方式,OpenAPI/Swagger 工具都能为我们自动生成可视化的 API 文档页面,极大提升前后端协作效率。

2. 在 Spring Boot 项目中引入 OpenAPI

我们使用 Gradle 构建项目,通过 Spring Initializr 创建一个基于 Kotlin、Spring Web 和 JDK 17 的项目。下载并导入项目后,只需添加以下三个依赖即可启用 OpenAPI 功能:

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

添加依赖后运行项目,访问 http://localhost:8080/swagger-ui.html 即可看到空的文档页面。接下来我们将为接口添加描述信息。

3. 从现有代码生成 OpenAPI 规范

很多项目在引入 OpenAPI 时,往往已有一定的开发历史。这些项目虽然暴露了接口,但新用户接入时往往因文档不全或过时而遇到困难。

将代码作为文档的唯一真实来源,可以确保文档始终与代码保持同步。这在对外提供 API 服务时尤为重要,因为你可以独立发布新版本接口并通知调用方更新。

3.1. 使用注解生成规范

要生成文档,我们需要对 REST 控制器和数据模型类添加注解。对于数据类,主要使用 @Schema 注解描述字段信息:

@Schema(description = "Model for a dealer's view of a car.")
data class DealerCar(
  @field:Schema(
    description = "A year when this car was made",
    example = "2021",
    type = "int",
    minimum = "1900",
    maximum = "2500"
  )
  val year: Int,
  // More fields
)

对于控制器方法,我们使用 @Operation@ApiResponses 注解描述接口行为和返回码:

@Operation(summary = "Sets a price for a chosen car", description = "Returns 202 if successful")
@ApiResponses(
  value = [
    ApiResponse(responseCode = "202", description = "Successful Operation"),
    ApiResponse(responseCode = "404", description = "Such a car does not exist"),
  ]
)
@PostMapping("/price/{carId}", consumes = ["application/json"])
fun setPrice(
  @PathVariable carId: Int,
  @RequestBody @OASRequestBody(
    description = "New price for the car",
    content = [Content(
      mediaType = "application/json",
      schema = Schema(type = "number", format = "float", minimum = "0.0", example = "23000.34"),
    )]
  ) price: BigDecimal
): ResponseEntity<Unit> {
    carService.setPrice(carId, price)
    return ResponseEntity.accepted().build()
}

⚠️ 注意:这种方式虽然强大,但注解数量可能迅速膨胀,影响代码可读性。如果你的接口设计变动频繁,建议优先从规范出发。

4. 从 OpenAPI 规范生成代码

无论是客户端对接还是服务端接口开发,手动编写重复的 HTTP 交互逻辑都容易出错且效率低下。通过规范生成代码,可以大幅提升开发效率。

此外,先定义规范也有助于前后端之间达成一致,避免频繁的接口变更。

4.2. 使用规范文件生成 Spring 服务端

首先,我们需要准备一个 OpenAPI 规范文件。你可以使用 Swagger 在线编辑器 编写,也可以从 GitHub 示例 获取。

然后,使用 OpenAPI Generator 插件生成服务端代码:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>7.6.0</version>
    <executions>
        <execution>
            <id>generateServer</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${basedir}/src/main/resources/car-spec.yaml</inputSpec>
                <generatorName>kotlin-spring</generatorName>
                <packageName>com.baeldung.openapi.car</packageName>
                <output>${project.build.directory}/generated-oas</output>
                <configOptions>
                    <dateLibrary>java8</dateLibrary>
                    <interfaceOnly>true</interfaceOnly>
                    <useTags>true</useTags>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

建议:记得将生成目录加入 Kotlin 编译路径,并在 sourceSets 中配置。

插件会生成接口类,我们只需实现具体逻辑即可:

class CarCrudController(private val carService: CarService) : CarsApi {
    override fun createCar(carBody: CarBody): ResponseEntity<Car> = TODO("Implementation")
    override fun getCar(id: Int): ResponseEntity<Car> = TODO("Implementation")
    override fun getCars(): ResponseEntity<List<Car>> = TODO("Implementation")
}

4.3. 使用规范生成客户端

与服务端类似,我们也可以从规范生成客户端代码。只需修改 generatorNamekotlin 即可:

<generatorName>kotlin</generatorName>

同时,添加必要的依赖支持 JSON 解析和网络请求:

<dependency>
    <groupId>com.squareup.moshi</groupId>
    <artifactId>moshi-kotlin</artifactId>
    <version>1.13.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.squareup.moshi</groupId>
    <artifactId>moshi-adapters</artifactId>
    <version>1.13.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
    <scope>test</scope>
</dependency>

使用客户端非常简单:

val car = CarsApi("http://localhost:8080")
  .createCar(ClientCarBody(model = "CM-X", make = "Gokyoro", year = 2021))

5. 总结

本文介绍了如何使用 OpenAPI(原 Swagger)实现以下功能:

✅ 从现有代码生成 API 规范
✅ 从规范生成服务端接口或客户端代码
✅ 自动生成用户友好的 API 文档页面

使用 OpenAPI 可以显著提升接口设计的规范性和协作效率,尤其是在跨团队或对外服务场景中。

完整代码示例可在 GitHub 上查看:kotlin-openapi 示例


原始标题:Using Swagger (OpenAPI) for a Spring REST API With Kotlin