主题
03 · OpenAPI 文件结构:四大块洋葱
生活类比:一份完整的
openapi.yaml就像一份正经的菜单—— 封面(餐厅名 + 地址)=info+servers, 菜品列表(菜名 + 价格 + 图)=paths, 通用配料表(番茄酱、薯条用在多个菜里)=components, 会员卡使用须知(支付方式)=security。
1. 一份最小可运行的 yaml
yaml
openapi: 3.0.3 # ① 用的哪一版规范
info: # ② API 基本信息
title: 小餐厅 API
version: 1.0.0
servers: # ③ 服务部署在哪
- url: https://api.example.com/v1
paths: # ④ 接口列表
/menu:
get:
responses:
'200':
description: OK必须有的字段只有 3 个:
openapi、info(含title+version)、paths。其他都是可选。
2. 四层洋葱结构
openapi: 3.0.3
│
├── info ← 元信息(标题、版本、联系人、协议)
├── servers ← 服务器列表(多环境)
├── tags ← 接口分组(用户、订单、商品...)
│
├── paths ← 主菜:所有接口
│ └── /users
│ └── get
│ ├── parameters ← 入参
│ ├── requestBody ← 请求体
│ ├── responses ← 响应
│ └── security ← 鉴权
│
├── components ← 复用区
│ ├── schemas ← 数据模型(User、Product…)
│ ├── parameters ← 通用参数(pageQuery、sortQuery…)
│ ├── requestBodies ← 通用请求体
│ ├── responses ← 通用响应
│ ├── headers ← 通用响应头
│ ├── securitySchemes ← 鉴权方案
│ └── examples ← 示例数据
│
├── security ← 全局鉴权(所有接口默认)
├── externalDocs ← 外链文档
└── webhooks ← 3.1+ 才有,第三方回调老的 OpenAPI 2 (Swagger 2) 用的是
definitions / parameters / responses平铺在顶层,3.0+ 全部统一塞进components里——结构清爽多了。
3. 一个一个字段拆开讲
3.1 openapi · 版本号
yaml
openapi: 3.0.3 # 推荐:3.0 稳定生态最广
# 或
openapi: 3.1.0 # 最新:完全兼容 JSON Schema 2020-123.2 info · 元信息
yaml
info:
title: 小餐厅 API # 必填
version: 1.0.0 # 必填,建议语义化版本(major.minor.patch)
description: |
多行描述,支持 **Markdown**。
可以放些链接、注意事项。
termsOfService: https://example.com/terms
contact:
name: 张三
email: zhangsan@example.com
url: https://example.com/support
license:
name: MIT
url: https://opensource.org/licenses/MIT在 Swagger UI 顶部那个"API 标题 + 描述"块就是从这儿来的。
3.3 servers · 多环境部署
yaml
servers:
- url: https://api.example.com/v1
description: 生产环境
- url: https://staging.api.example.com/v1
description: 测试环境
- url: http://localhost:3000/v1
description: 本地
# 可以用变量
- url: https://{region}.api.example.com/{version}
variables:
region:
default: cn-east
enum: [cn-east, us-west, eu-central]
version:
default: v1Swagger UI 顶部会出现一个下拉框,让你选环境。Try it out 时按当前选中的 URL 发请求。
3.4 tags · 接口分组
yaml
tags:
- name: 用户
description: 用户注册、登录、修改资料
externalDocs:
url: https://wiki.example.com/user
- name: 订单
description: 下单、支付、退款
- name: 商品然后在每个接口里:
yaml
paths:
/users:
get:
tags: [用户] # 这个接口归属于"用户"分组
...UI 里就会按 tag 折叠分组——接口一多,强烈推荐用 tags。
3.5 paths · 接口列表(核心,第 4 章详讲)
yaml
paths:
/users: # 路径
get: { ... } # GET /users
post: { ... } # POST /users
/users/{id}: # 带路径参数
get: { ... }
put: { ... }
delete: { ... }3.6 components · 复用区(核心,第 6 章详讲)
yaml
components:
schemas:
User: # 定义一个 User 数据模型
type: object
properties:
id: { type: integer }
name: { type: string }
required: [id, name]
parameters:
PageQuery: # 定义一个通用参数
name: page
in: query
schema:
type: integer
default: 1
responses:
NotFound: # 通用 404 响应
description: 资源不存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
bearerAuth: # 鉴权方案
type: http
scheme: bearer引用方式($ref):
yaml
paths:
/users:
get:
parameters:
- $ref: '#/components/parameters/PageQuery'
responses:
'404':
$ref: '#/components/responses/NotFound'
$ref是 OpenAPI 的"复用引擎"——下一节细讲。
3.7 security · 全局鉴权
yaml
# 全局:所有接口默认要 bearer 鉴权
security:
- bearerAuth: []
paths:
/login:
post:
security: [] # 单个接口可以覆盖:登录接口免鉴权4. $ref 引用机制——Swagger 的"灵魂"
4.1 为什么要 $ref
不复用:
yaml
# 错示范:每个接口里把 User 的字段抄一遍
paths:
/users/1:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id: { type: integer }
name: { type: string }
email: { type: string }
... (重复 50 行)
/users/2:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id: { type: integer }
name: { type: string }
email: { type: string }
... (又抄一遍 😱)复用:
yaml
components:
schemas:
User:
type: object
properties:
id: { type: integer }
name: { type: string }
email: { type: string }
paths:
/users/1:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/User' # ✅ 一行搞定4.2 $ref 的语法
yaml
# 当前文件内引用(最常见)
$ref: '#/components/schemas/User'
# 同目录其他文件
$ref: './schemas/user.yaml'
$ref: './schemas/user.yaml#/User'
# 远程 URL(不推荐)
$ref: 'https://example.com/schemas/user.yaml'路径里的
#是 JSON Pointer 语法,/components/schemas/User表示按 key 一层层往下找。
4.3 常见错误
yaml
# ✗ 错:少了 #
$ref: 'components/schemas/User'
# ✗ 错:拼写
$ref: '#/components/schema/User' # schemas 漏了 s
# ✗ 错:循环引用(A ref B、B ref A)
# 工具会无限展开,要么报错要么死循环
# ✗ 错:把 $ref 和别的字段并列
schema:
$ref: '#/components/schemas/User'
description: "用户对象" # 会被忽略!$ref 必须独占5. YAML vs JSON:选哪个?
OpenAPI 文件可以是 yaml 或 json,等价。
yaml
# YAML 写法
openapi: 3.0.3
info:
title: My API
version: 1.0.0json
// JSON 写法
{
"openapi": "3.0.3",
"info": {
"title": "My API",
"version": "1.0.0"
}
}| 维度 | YAML | JSON |
|---|---|---|
| 可读性 | ⭐⭐⭐⭐⭐ (无括号、无引号) | ⭐⭐⭐ |
| 注释 | ✅ 支持 # | ❌ 不支持 |
| 体积 | 小 30% | 大 |
| 工具兼容 | 全支持 | 全支持 |
| 容易出错 | 缩进错容易踩坑 | 大括号配对易出错 |
手写选 yaml,机器生成(如后端框架自动导出)通常是 json。两者可以用
yq/js-yaml互转。
6. 一份带所有顶层字段的"完整骨架"
复制这份,按需删减:
yaml
openapi: 3.0.3
info:
title: 你的 API 名字
version: 1.0.0
description: |
详细描述。
支持 Markdown:**加粗**、[链接](https://example.com)。
contact:
name: 张三
email: zhangsan@example.com
license:
name: MIT
servers:
- url: https://api.example.com/v1
description: 生产
- url: http://localhost:3000/v1
description: 本地
tags:
- name: user
description: 用户管理
- name: order
description: 订单管理
security:
- bearerAuth: [] # 全局默认 token 鉴权
paths:
/ping:
get:
tags: [system]
summary: 健康检查
security: [] # 这个接口免鉴权
responses:
'200':
description: pong
content:
text/plain:
schema:
type: string
example: pong
components:
schemas:
User:
type: object
properties:
id: { type: integer }
name: { type: string }
required: [id, name]
Error:
type: object
properties:
code: { type: integer }
message: { type: string }
parameters:
PageQuery:
name: page
in: query
schema: { type: integer, default: 1 }
responses:
NotFound:
description: 资源不存在
content:
application/json:
schema: { $ref: '#/components/schemas/Error' }
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
externalDocs:
description: 完整 Wiki
url: https://wiki.example.com/api这就是后续所有章节都会基于的"骨架"。背下来,写得快。
7. 多文件拆分 · 项目大了怎么办?
接口一多,单文件 5000 行没法维护。按模块拆:
api/
├── openapi.yaml ← 主文件,只放顶层 + ref
├── paths/
│ ├── users.yaml
│ ├── orders.yaml
│ └── products.yaml
└── schemas/
├── user.yaml
├── order.yaml
└── common.yaml主文件这样写:
yaml
# openapi.yaml
openapi: 3.0.3
info:
title: 大型 API
version: 1.0.0
paths:
/users:
$ref: './paths/users.yaml#/Users'
/orders:
$ref: './paths/orders.yaml#/Orders'
components:
schemas:
User:
$ref: './schemas/user.yaml#/User'用
redocly bundle/swagger-cli bundle命令可以把多文件合并成一份发布文件。
8. 章末面试题速览
- OpenAPI 的根字段必填的有哪几个? →
openapi、info(含title、version)、paths。 $ref和allOf的区别? →$ref是引用一个 Schema 整体;allOf是把多个 Schema 合并(继承)。- 多环境部署怎么在文档里体现? →
servers数组里写多个 URL,UI 顶部下拉切换。
🎬 可视化演示
下方 demo 用一个可折叠的洋葱图让你点进每一层,看清 info / servers / paths / components 各自是什么。
→ 打开 03_openapi_spec/demo.html
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗