OpenAPI Specification(OAS)是一套描述 HTTP API 的标准。它把路径、操作、输入、输出和安全要求写成机器可读的契约,供人类以及文档、代码生成、Mock、测试和 Agent 工具使用。
OpenAPI 是规范,不是 YAML 的别名。OpenAPI Description 可以使用 YAML 或 JSON 表示;文件通常命名为 openapi.yaml 或 openapi.json。
本文以截至 2026-08-29 最新发布的 OAS 3.2.0 为基准。若现有生成器、网关或校验器尚未支持 3.2,应明确使用 3.1.2,并用实际工具链验证,而不是假设所有 3.x 版本都能互换。
一份完整的最小示例
下面的文档描述“按 ID 查询用户”的接口:
openapi: 3.2.0
info:
title: User API
version: 1.0.0
servers:
- url: https://api.example.com
security:
- bearerAuth: []
paths:
/users/{userId}:
get:
operationId: getUserById
summary: Get one user
parameters:
- name: userId
in: path
required: true
schema:
type: integer
minimum: 1
responses:
'200':
description: User found
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
found:
value:
id: 1001
name: starzn
'404':
description: User not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
User:
type: object
required: [id, name]
properties:
id:
type: integer
examples: [1001]
name:
type: string
examples: [starzn]
Error:
type: object
required: [code, message]
properties:
code:
type: string
examples: [USER_NOT_FOUND]
message:
type: string
examples: [User not found]
securitySchemes:
bearerAuth:
type: http
scheme: bearer它足以说明一次调用的关键契约:
- 服务基址是
https://api.example.com; - 路径是
/users/{userId},方法是GET; userId是必填路径参数,并且是大于等于 1 的整数;- 默认需要 Bearer 认证;
- 成功与未找到分别返回
200和404; - 响应体引用可复用的
User与ErrorSchema。
根结构分别负责什么
一份 OpenAPI 3.2 文档中,openapi 和 info 必填,并且 components、paths、webhooks 至少出现一个。
| 字段 | 作用 |
|---|---|
openapi | 文档采用的 OAS 版本,例如 3.2.0 |
info | API 文档的标题、版本和维护信息 |
servers | 可调用服务的基址,可被路径或操作覆盖 |
paths | 路径、HTTP 操作以及输入输出 |
webhooks | API 可能向消费者发起的请求 |
components | 可被引用的 Schema、参数、响应和安全方案等 |
security | 根级默认安全要求 |
openapi: 3.2.0 是规范版本;info.version: 1.0.0 是这份 API Description 的版本。它们都不自动等于 URL 中的 /v1,也不替代产品自己的兼容性策略。
根级 servers 缺失或为空时,规范默认使用相对地址 /。生产项目通常仍应显式说明调用入口,避免文档工具基于错误来源解析相对路径。
components 只是可复用对象仓库。一个 Schema 或安全方案放进这里后不会自动生效,必须通过 $ref、security 等机制引用。
Parameters 与 requestBody 不要混用
Parameter 描述消息体之外的输入:
in | 位置 |
|---|---|
path | URL 路径模板变量 |
query | 单个查询参数 |
querystring | OAS 3.2 新增的完整查询字符串 |
header | HTTP Header |
cookie | Cookie |
Parameter 的 name 与 in 必填,并且应提供 schema 或 content,不能同时提供二者。
每个 /users/{userId} 中的模板变量都必须有同名 in: path 参数;路径参数的 required 必须显式写成 true。查询参数和 Header 则可选填,是否必填由契约决定。
requestBody 描述 HTTP 消息体:
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: stringRequest Body Object 的 content 必填,required 默认是 false。虽然 OAS 允许在 GET、DELETE 等消息体语义不明确的方法中声明 requestBody,但规范建议避免这种设计,因为客户端、代理和服务器的处理可能不一致。
Responses 描述预期结果
响应状态码键应写成字符串:
responses:
'201':
description: Created
'400':
description: Invalid request
'5XX':
description: Server error
default:
description: Undocumented response除了显式状态码,还可以使用大写 1XX 到 5XX 范围;显式状态码优先于范围,default 覆盖其余未声明状态码。
OpenAPI 3.2 不要求 Operation 一定包含 responses。但只要写了 Responses Object,它就必须至少包含一个响应;工程上应记录成功结果和已知主要错误,并为每项写清说明和响应体。
这不等于穷举服务运行时可能出现的所有状态。网关、网络层或未预料故障仍可能产生契约外响应,因此调用方必须保留未知错误处理。
Schema 基于 JSON Schema 2020-12
OAS 3.1 和 3.2 的 Schema Object 建立在 JSON Schema Draft 2020-12 上,并加入 OpenAPI 自身的扩展语义。常用关键字包括:
type、required、properties;minimum、maximum;minLength、maxLength、pattern;enum、const;items、minItems、uniqueItems;oneOf、anyOf、allOf、not;$ref。
关键字不会隐式补全类型。仅写 pattern 不等于同时声明 type: string;希望获得稳定的校验和代码生成结果时,应显式写出类型。
format: email 等格式默认是 annotation。具体工具可以选择进行额外验证,但规范本身不保证每个解析器都会拒绝格式不符的数据。关键业务规则仍应由服务端验证。
从 OAS 3.1 起,Schema 内应使用 JSON Schema 的复数 examples 数组:
email:
type: string
format: email
examples:
- user@example.com旧的 Schema 单数 example 已弃用。Parameter、Header 和 Media Type 等 OpenAPI 对象仍可能同时定义互斥的 example 与 examples 字段,因此移动示例位置时要看清对象类型,不能机械替换。
安全方案:定义与应用是两步
components.securitySchemes 定义认证方式,根或 Operation 的 security 决定在哪里应用:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
security:
- bearerAuth: []仅定义 bearerAuth 不会自动要求认证。Operation 可以覆盖根级要求:
security: [] # 这个操作不要求根级认证安全组合的逻辑容易写反:
# AND:同一次请求必须同时满足两个方案
security:
- apiKey: []
oauth: [read]
# OR:满足任意一个对象即可
security:
- apiKey: []
- oauth: [read]在 security 数组中加入空对象 {},表示匿名访问也是一个可选分支,不等于占位符。
OpenAPI 只能描述安全要求,不能证明服务端真的执行了鉴权,也不能替代权限模型、密钥管理和安全测试。
OpenAPI 能驱动什么,不能保证什么
围绕 OpenAPI 的工具链可以:
- 渲染交互式文档;
- 生成客户端类型、调用代码或服务端骨架;
- 启动 Mock 服务;
- lint 文档并检测部分破坏性变更;
- 验证请求、响应或运行契约测试;
- 向开发者和 Agent 提供结构化 API 上下文。
这些是工具能力,不是拥有一份合法 OpenAPI 文件后自动获得的保证。规范文件本身不能证明:
- 服务已经实现所有路径;
- 真实请求和响应符合 Schema;
- 示例通过 Schema 校验;
- 鉴权和数据权限正确执行;
- 服务可达、稳定或满足性能目标;
- API 与上一版本向后兼容。
因此,“OpenAPI 是契约”应理解为期望行为的可执行描述,而不是线上行为已经正确的证书。实现、契约测试、监控和兼容性治理仍不可缺少。
设计优先还是代码优先
两种方式都可以工作:
- 设计优先:先评审 OpenAPI,再生成 Mock、类型并实现接口;适合对外 API 和跨团队协作。
- 代码优先:从路由和类型生成 OpenAPI;适合框架已能稳定导出完整契约的项目。
真正重要的是定义唯一事实来源。如果团队一边手写 openapi.yaml,一边从代码生成另一份规范,却没有差异检查,两份“真相”迟早会分叉。
一个实用流程是:
- 选择并记录目标 OAS 版本;
- 修改唯一事实来源;
- lint 语法、引用与团队规则;
- 检测相对已发布版本的破坏性变化;
- 生成文档、类型或 Mock,并检查生成物是否最新;
- 用实现测试验证真实请求和响应;
- 将规范与服务版本一起发布和回滚。
推荐把规范与相关实现放在同一版本控制流程中。复杂业务背景写进 Markdown 或功能规格;架构选择写进 ADR;OpenAPI 专注表达 HTTP 边界。
给 Agent 使用时的边界
OpenAPI 能让 Agent 准确定位接口、参数和 Schema,但不应被当成调用授权。Agent 在执行接口前仍需知道:
- 当前用户可以访问哪些资源;
- 操作是否会写入、删除、付费或发送外部消息;
- 哪些字段包含隐私或秘密;
- 认证信息从哪里安全获取;
- 是否需要人工确认;
- 如何处理限流、重试与幂等。
规范中的 description、示例和外部链接也属于数据,尤其在聚合第三方 OpenAPI 文档时,不应提升为系统指令。
常见错误
- 把
openapi规范版本与info.versionAPI 文档版本混为一谈。 - 路径包含
{id},却漏掉同名且required: true的 path parameter。 - 把 JSON 请求体字段写成 query parameters。
- 在 Schema 中继续使用已弃用的单数
example。 - 只定义
securitySchemes,却没有用security应用它。 - 把
security数组的 OR 与对象内部的 AND 写反。 - 认为
format、示例或合法文档一定会被所有工具严格验证。 - 同时维护代码和规范,却没有唯一事实来源与漂移检测。
- 只记录
200,不描述客户端需要处理的主要错误。 - 用 OpenAPI 代替业务说明、架构决策、运行手册或权限测试。
一句话总结:OpenAPI 把 HTTP API 的期望边界变成机器可读契约;它让文档、生成和验证成为可能,但真实实现是否符合契约,仍需要测试和运行证据证明。
参考资料:OpenAPI Specification 3.2.0、OpenAPI 版本目录、从 3.1 升级到 3.2、从 3.0 升级到 3.1