4、OpenAPI核心结构:info、servers、paths、components、security
OpenAPI 规范,说白了就是一份机器能读懂、人也能看懂的 API 说明书。我最早接触它的时候,觉得不就是个 JSON 文件嘛,有啥了不起的。直到有一次团队因为接口文档和代码对不上,线上出了事故……嗯,从那以后我才真正重视起这个“说明书”的结构。
一份完整的 OpenAPI 文档,核心就五个部分:info、servers、paths、components、security。你把这五个搞明白了,写出来的文档就不会跑偏。
一句话总结:info 是身份证,servers 是地址,paths 是业务逻辑,components 是公共零件库,security 是门禁系统。
4.1 info — API 的身份证
info 字段是文档的“户口本”。你想想看,别人拿到你的 API 文档,第一眼看到的就是这里。我习惯把 info 写得尽量详细,尤其是 description 字段,别只写一句话,把 API 的用途、适用场景、甚至联系方式都放进去。
openapi: "3.0.3"
info:
title: 用户服务 API
version: "2.1.0"
description: |
提供用户注册、登录、信息管理等基础能力。
适用于内部微服务调用和前端 H5 页面。
contact:
name: API 团队
email: api@example.com
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0
我的习惯:version 字段用语义化版本号(major.minor.patch),每次接口变更都跟着升级。我曾经见过一个项目,version 永远写 1.0.0,结果线上跑着三个不同版本的接口,全乱套了。
4.2 servers — 告诉客户端往哪发请求
servers 字段定义了 API 的访问地址。你可能觉得这很简单,不就是写个 URL 嘛。但我在项目中踩过坑——开发、测试、生产三个环境的地址不一样,文档里只写了一个,结果前端同学直接复制到线上,出了大问题。
所以,我建议你这样做:
- 把多个环境都列出来,用
description标注清楚 - 支持变量替换,方便动态切换
- 如果 API 有版本前缀(比如
/v2/),也写在 servers 里
servers:
- url: https://api.example.com/v2
description: 生产环境
- url: https://staging-api.example.com/v2
description: 预发布环境
- url: http://localhost:8080/v2
description: 本地开发
注意:不要在生产文档里暴露内网地址或带敏感信息的 URL。我曾经见过有人把 localhost:3306 写进 servers,那可不是 API 地址,是数据库地址!
4.3 paths — 业务逻辑的核心战场
paths 是 OpenAPI 文档里最庞大的部分。每个路径对应一个资源,每个资源下面有若干操作(GET、POST、PUT、DELETE)。我个人习惯把 paths 按业务模块分组,用 tags 来区分。
举个例子,用户模块的接口:
paths:
/users:
get:
tags: [用户管理]
summary: 获取用户列表
parameters:
- name: page
in: query
schema:
type: integer
responses:
'200':
description: 成功返回用户列表
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
post:
tags: [用户管理]
summary: 创建新用户
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: 用户创建成功
这里有个关键点——$ref 引用。你想想看,如果每个接口都重复写一遍 User 的数据结构,文档会变得又臭又长。所以,我们把公共模型抽到 components 里,paths 里只负责引用。
4.4 components — 你的公共零件库
components 是 OpenAPI 的“复用神器”。它里面可以定义:
| 子字段 | 用途 | 我常用的场景 |
|---|---|---|
schemas |
数据模型定义 | User、Order、Product 等实体 |
parameters |
公共参数 | 分页参数、排序参数 |
responses |
公共响应 | 统一错误响应、401 未授权 |
requestBodies |
公共请求体 | 批量操作请求体 |
headers |
公共请求头 | X-Request-Id、X-Trace-Id |
举个例子,定义一个通用的分页响应模型:
components:
schemas:
PaginatedResponse:
type: object
properties:
data:
type: array
items:
type: object
total:
type: integer
page:
type: integer
pageSize:
type: integer
required:
- data
- total
- page
- pageSize
我的经验:components 里的模型一定要加 required 字段。我曾经漏掉这个,结果前端以为某个字段是可选的,上线后才发现接口报错。嗯,从那以后我每个模型都检查一遍 required。
4.5 security — 把门看好
security 字段定义了 API 的认证方式。常见的方案有三种:
- :简单粗暴,适合内部服务
- HTTP Basic Auth:老牌方案,现在用得少了
- OAuth2:灵活强大,适合开放平台
我建议你在 components/securitySchemes 里先定义好认证方案,然后在全局或每个路径上引用。
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
Auth:
type:
in: header
name: X-
# 全局安全配置
security:
- BearerAuth: []
- Auth: []
避坑指南:我曾经见过一个项目,security 定义在全局,但某个公开接口(比如注册、登录)根本不需要认证。结果客户端调用时还得传一个空的 ,多此一举。正确的做法是:全局配置默认安全策略,然后在不需要认证的路径上覆盖 security: []。
4.6 五个部分如何协同工作
这五个部分不是孤立的。我画个场景你就明白了:
- info 告诉客户端:“我是用户服务 API,版本 2.1”
- servers 告诉客户端:“你往
https://api.example.com/v2发请求” - paths 定义:“
/users路径支持 GET 和 POST” - components 提供:“User 模型长这样,分页参数长那样”
- security 要求:“请求必须带 JWT ”
你看,每一层各司其职,组合起来就是一份完整的 API 契约。我在团队里推行数据契约驱动开发时,就是拿这个五层结构当模板,让大家照着填。效果还不错,至少再也没出现过“文档和代码对不上”的尴尬局面。
核心要点:info 写清楚、servers 写全、paths 写准、components 写复用、security 写严谨。这五个点抓住了,OpenAPI 文档的质量就上去了。