1. 引言

软件工程行业对 Web API 的依赖日益加深,这主要归因于云计算和 HTTP 协议的普及。开发团队必须确保设计出实用且友好的 API。传统开发方法的核心痛点在于:在同步创建 API 契约和实现业务逻辑时,难以保持敏捷性

本文将介绍使用 Spring Boot 和 OpenAPI 3.0 规范的 API 优先开发方法。这种方式通过及时的 API 设计反馈、快速失败流程和并行工作,显著提升团队沟通效率和敏捷性

2. OpenAPI 规范是什么

OpenAPI 规范(OAS)标准化了 API 设计文档的创建方式。使用 OAS 的 API 优先工作流通常包含以下步骤:

  • 团队创建设计文档,分享给相关方收集反馈并迭代修改
  • 当团队与利益相关者达成 API 设计共识后,开发者通过代码生成工具基于文档创建服务端骨架代码
  • 开发者基于生成的代码开始实现业务逻辑

OAS 3.1 支持定义 HTTP 资源、动词、响应码、数据模型、媒体类型、安全方案等 API 组件。

3. 为什么选择 API 优先开发

敏捷开发 是软件行业最主流的方法论之一。敏捷的核心在于:快速构建最小可行产品,要么快速失败并调整初始设计,要么在此基础上逐步迭代

从敏捷团队视角看,API 优先开发具备明显优势:

  • ✅ 快速获取 API 设计反馈
  • ✅ 建立 API 契约共识的单一沟通渠道
  • ✅ 支持相关人员并行工作

为充分理解 API 优先的优势,我们对比两个敏捷团队的工作场景:传统开发 vs API 优先开发:

api first vs traditional

在传统场景中,开发者接到新功能开发任务后,通常先实现业务逻辑,再将其与代码中的 API 设计关联。只有当开发者完成该功能的所有代码修改后,API 才能供利益相关者评审。这导致 API 契约评审和共识过程缓慢且容易产生误解

而在 API 优先开发中,设计师在业务逻辑开发阶段前就创建 API 契约文档。该文档为产品利益相关者提供了评估工作量、及时反馈、创建测试用例、编写 API 文档等的通用语言。我们可以在浪费任何开发时间前,快速调整初始设计或推进实施,显著提升敏捷性

API 优先开发的另一个核心优势是:文档创建后,多人可并行推进同一功能开发,例如:

  • 产品经理评估风险、设计新功能、管理时间线
  • 测试工程师构建测试场景
  • 技术文档工程师编写 API 文档
  • 开发者实现业务逻辑代码

4. 定义 API 契约

我们通过一个银行演示 REST API 说明 API 优先工作流。该 API 支持查询余额和存款操作。下表展示了资源路径、HTTP 动词和响应码(RC):

HTTP 动词 资源 错误响应码 成功响应码
GET /account 404 – 账户不存在 200 – 获取余额信息
POST /account/deposit 404 – 账户不存在 204 – 存款操作完成

现在创建 OAS API 规范文件。我们将使用 Swagger 在线编辑器,这是一个将 YAML 解析为 Swagger 文档的在线工具。

4.1. API 顶层上下文

首先定义 API 的顶层上下文。在 Swagger 编辑器 中,用以下 YAML 代码替换编辑器左侧内容:

openapi: 3.0.3
info:
  title: 银行账户操作 API 规范
  description: |-
    简单的银行 API,支持两种操作:
    - 根据账号查询账户余额
    - 向指定账户存款
  version: 1.0-SNAPSHOT
servers:
  - url: https://testenvironment.org/api/v1
  - url: https://prodenvironment.org/api/v1
tags:
  - name: accounts
    description: 银行账户相关操作

⚠️ 注意:当前出现的错误可忽略,它们不会阻塞工作流,后续步骤会自动解决。

逐个解析关键字:

  • openapi – 使用的 OAS 版本
  • title – API 的简短标题
  • description – API 职责描述
  • version – API 当前版本(如 1.0-SNAPSHOT)
  • servers – 客户端可访问 API 的服务器地址
  • tags – 用于对 API 操作分组的唯一标签集合

4.2. 暴露 API 路径

现在创建前文描述的 GET /account 和 POST /account/deposit 接口。在 YAML 编辑器根级别添加以下内容:

paths:
  /account:
    get:
      tags:
        - accounts
      summary: 获取账户信息
      description: 根据账号获取账户信息
      operationId: getAccount
      responses:
        200:
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Account'
        404:
          description: 账户不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountNotFoundError'
  /account/deposit:
    post:
      tags:
        - accounts
      summary: 向账户存款
      description: 向指定账户存入指定金额
      operationId: depositToAccount
      requestBody:
        description: 账号和存款金额
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepositRequest'
        required: true
      responses:
        204:
          description: 成功
        404:
          description: 账户不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountNotFoundError'

⚠️ 注意:YAML 解释器会显示错误,我们将在 4.3 节解决,当前可忽略。

上述文档内容较多,逐个解析关键字:

  • paths – 定义 API 资源 /account/account/deposit,需指定支持的 getpost 动词
  • tags – 所属分组(需与 4.1 节的标签名一致)
  • summary – 接口功能的简要说明
  • description – 接口工作原理的详细说明
  • operationId – 操作的唯一标识符
  • requestBody – 请求载荷,包含 descriptioncontentrequired 关键字(内容 schema 在 4.3 节定义)
  • responses – 所有可用响应码列表,每个响应码对象包含 descriptioncontent(内容 schema 在 4.3 节定义)
  • content – 消息的 HTTP Content-Type

4.3. 定义数据模型组件

最后创建 API 的数据模型对象:请求/响应体和错误消息。在 YAML 编辑器根级别添加以下结构:

components:
  schemas:
    Account:
      type: object
      properties:
        balance:
          type: number
    AccountNotFoundError:
      type: object
      properties:
        message:
          type: string
    DepositRequest:
      type: object
      properties:
        accountNumber:
          type: string
        depositAmount:
          type: number

添加上述内容后,编辑器中的所有解释错误应消失。

上述 YAML 代码定义了 4.2 节 schema 关键字中使用的组件。组件可无限次复用,例如 AccountNotFoundError 对象同时用于两个接口的 404 响应。逐个解析关键字:

  • components – 组件的根级别关键字
  • schemas – 所有对象定义的列表
  • type – 字段类型(使用 object 类型时必须定义 properties
  • properties – 对象所有字段名及其类型的列表

4.4. 评审 API 文档

此时 API 已在线可供产品利益相关者评审。API 优先开发的核心优势在于:无需进入开发阶段就能快速验证设计可行性。因此,在进入开发阶段前,务必确保所有相关人员评审并确认 API 资源、响应码、数据模型及接口描述

一旦团队达成设计共识,即可并行推进 API 开发工作。

5. 导入 Spring Boot 应用

本节展示开发者如何将 YAML 文档导入应用并自动生成 API 骨架代码。

首先在 /src/main/resources 文件夹创建空 YAML 文件 account_api_description.yaml,将 Swagger 在线编辑器中的完整 YAML 代码粘贴其中。然后在 Spring Boot 应用的 pom.xml 文件 标签中添加 openapi-generator-maven-plugin 插件:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>6.2.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <skipValidateSpec>true</skipValidateSpec>
                <inputSpec>./src/main/resources/account_api_description.yaml</inputSpec>
                <generatorName>spring</generatorName>
                <configOptions>
                    <openApiNullable>false</openApiNullable>
                    <interfaceOnly>true</interfaceOnly>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

本文代码参考自 OpenAPI 插件教程

现在运行以下命令从 YAML 文件生成服务端代码:

mvn clean install

完成后可在 target 文件夹查看生成的代码:

openapi3 code generated spring app

开发者可将生成的类作为开发阶段的起点。例如通过以下 AccountController 类实现 AccountApi 接口:

@Controller
public class AccountController implements AccountApi {
    @Override
    public ResponseEntity<Void> depositToAccount(DepositRequest depositRequest) {
        // 通过 Service/Utils/Repository 类执行业务逻辑
        return AccountApi.super.depositToAccount(depositRequest);
    }

    @Override
    public ResponseEntity<Account> getAccount() {
        // 通过 Service/Utils/Repository 类执行业务逻辑
        return AccountApi.super.getAccount();
    }
}

重写的 depositToAccountgetAccount 方法分别对应 POST /account/deposit 和 GET /account 接口。

6. 结论

本文介绍了使用 Spring Boot 和 OAS 进行 API 优先开发的方法,分析了 API 优先的优势及其对现代敏捷开发团队的助力。采用 API 优先的核心价值在于:提升敏捷性,减少 API 开发中的时间浪费。通过该方法,我们能快速起草、迭代设计并获取反馈。

采用 API 优先的另一重要原因是:利益相关者无需等待开发者完成代码即可启动工作。在初始 API 设计文档创建后,测试、文档、管理和开发人员可并行推进工作。

如往常一样,本文代码可在 GitHub 获取。


原始标题:API First Development with Spring Boot and OpenAPI 3.0 | Baeldung

« 上一篇: Maven Reactor