2. OpenAPI 规范基础:历史、核心结构与文件组成

OpenAPI 规范(原 Swagger 规范)是 RESTful API 契约的事实标准。理解其演进脉络、3.0 版的核心骨架以及 YAML/JSON 文件的组成要素,是划定 API 契约领域边界的第一步。本章从这三个维度建立基础认知。

2.1 OpenAPI 规范的历史演进

规范经历了从 Swagger 到 OpenAPI 的品牌与治理转变,每一次大版本都显著影响了契约的表达能力。

版本 发布时间 关键变化 治理组织
Swagger 1.x 2011 首次定义 REST API 描述格式,支持 JSON Wordnik / 社区
Swagger 2.0 2014 引入 definitions、parameters、responses 可复用组件;成为业界主流 Swagger 社区
OpenAPI 3.0 2017 重构为 components 对象;新增 oneOf/anyOf/allOf 组合模型;分离请求体与参数;支持回调、链接 OpenAPI Initiative (Linux Foundation)
OpenAPI 3.1 2021 完全兼容 JSON Schema 2020-12;引入 webhooks 顶层字段;移除 nullable 改用 type: ["string", "null"] OpenAPI Initiative
领域边界提示:OpenAPI 3.0 是当前最广泛采用的稳定版本。本课程所有契约边界分析均以 OpenAPI 3.0.x 为基准,部分高级话题会对比 3.1 的差异。

2.2 OpenAPI 3.0 核心结构

一个 OpenAPI 3.0 文档由四个顶层区域构成,它们共同定义了 API 的契约边界:

  1. 元信息层(openapi、info、servers)—— 声明规范版本、API 标题、版本号、基础 URL。
  2. 路径层(paths)—— 按资源路径组织所有端点及其操作(GET/POST/PUT/DELETE 等)。
  3. 组件层(components)—— 集中定义可复用的 Schema、参数、请求体、响应、安全方案等。
  4. 增强层(tags、externalDocs、security)—— 提供分组、外部文档、全局安全声明。
OpenAPI 3.0 文档核心结构 元信息层 openapi: "3.0.3" info: { title, version, description } servers: [ { url, description } ] → 定义 API 身份与入口地址 路径层 paths: /orders: get: { operationId, parameters, responses } post: { requestBody, responses } 组件层 components: schemas: { Order, Customer, … } parameters: { orderId, … } requestBodies: { CreateOrder, … } 增强层 tags: [ { name, description } ] externalDocs: { url, description } security: [ { apiKey: [] } ] 四层结构共同构成 API 契约的完整领域边界

2.3 OpenAPI 文件的基本组成

一个完整的 OpenAPI 3.0 文件(YAML 或 JSON)包含以下必需和可选字段。以下是一个最小可用的契约示例:

openapi: "3.0.3"
info:
  title: 订单服务 API
  version: "1.0.0"
  description: 管理订单的创建、查询与状态变更
servers:
  - url: https://api.example.com/v1
    description: 生产环境
paths:
  /orders:
    get:
      summary: 查询订单列表
      operationId: listOrders
      parameters:
        - name: status
          in: query
          schema:
            type: string
      responses:
        "200":
          description: 成功返回订单列表
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Order"
components:
  schemas:
    Order:
      type: object
      properties:
        id:
          type: integer
        customerName:
          type: string
        totalAmount:
          type: number
      required:
        - id
        - customerName

2.4 各组成要素详解

字段 必需 说明 领域边界意义
openapi 是 声明使用的 OpenAPI 规范版本号 确定契约解析规则与能力集
info 是 API 的元数据:标题、版本、描述、联系人等 标识 API 所属业务域与版本边界
servers 否(推荐) 一个或多个基础 URL,可带变量 划定 API 的网络可达边界
paths 是 按资源路径组织的端点定义 定义资源边界与操作集合
components 否 可复用的 Schema、参数、请求体、响应、安全方案 统一类型系统,防止契约碎片化
tags 否 用于对路径进行逻辑分组 映射到领域子域或模块边界
security 否 全局安全要求声明 定义访问控制边界
关键认知:OpenAPI 文件不仅仅是接口文档,它是一份可执行的契约。每个字段都在划定 API 的某个领域边界——资源边界、类型边界、版本边界、安全边界。在后续章节中,我们将基于这些边界进行领域驱动设计分析。

2.5 路径与操作的契约结构

每个路径下的操作(Operation)是契约的核心单元,其内部结构决定了 API 的行为边界:

  • operationId —— 操作的唯一标识符,在代码生成和领域事件溯源中作为方法签名。
  • parameters —— 路径参数、查询参数、请求头参数,定义输入边界。
  • requestBody —— 仅适用于 POST/PUT/PATCH,描述请求体的媒体类型与 Schema。
  • responses —— 按 HTTP 状态码组织的响应定义,包含媒体类型与 Schema。
  • security —— 可覆盖全局安全策略,定义操作级安全边界。
路径操作(Operation)内部结构 /orders/{orderId} GET listOrders parameters - name: orderId in: path, required: true requestBody content: application/json responses "200": { description, content } "404": { description } security: [ { bearerAuth: [] } ] ← 操作级安全边界 可覆盖全局 security,实现细粒度访问控制
常见误区:初学者常将 requestBody 与 parameters 混淆。在 OpenAPI 3.0 中,parameters 仅用于路径、查询、请求头、Cookie 参数;请求体必须使用独立的 requestBody 字段。这一分离使得契约的输入边界更加清晰。

2.6 组件复用与契约边界

components 对象是 OpenAPI 3.0 最重要的架构改进之一。它将类型定义从路径中抽离,形成独立的类型系统:

components:
  schemas:
    Order:
      type: object
      properties:
        id: { type: integer }
        items:
          type: array
          items:
            $ref: "#/components/schemas/OrderItem"
    OrderItem:
      type: object
      properties:
        productId: { type: integer }
        quantity: { type: integer }
        price: { type: number }
  parameters:
    orderId:
      name: orderId
      in: path
      required: true
      schema: { type: integer }
  requestBodies:
    CreateOrder:
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Order"

通过 $ref 引用,路径层可以复用组件层的定义。这种机制带来的领域边界优势:

  • 单一事实来源 —— Order 类型只定义一次,所有路径引用同一 Schema。
  • 类型一致性 —— 避免不同路径对同一资源定义不一致的字段。
  • 版本管理 —— 修改组件 Schema 即可全局生效,便于契约版本演进。
  • 领域模型映射 —— components/schemas 直接对应领域驱动设计中的聚合根、实体、值对象。
实践建议:在编写 OpenAPI 契约时,优先将业务实体定义为 components/schemas,路径层只做引用。这能强制团队在 API 设计阶段就思考领域模型的边界,而非仅仅罗列端点。