前面四篇我们把接口”设计得规范、安全、一致”,但还有一个绕不开的现实问题:别人怎么知道你的接口长什么样、该怎么调? 答案就是 API 文档。
糟糕的团队靠”口头约定 + 微信截图 + 口口相传”,结果一个人离职,接口知识就失传了。专业的做法是:文档即契约,且尽量自动生成。这一篇我们讲 OpenAPI 规范、Swagger UI 在线调试,以及怎么让文档”不写也更新”。
为什么文档是 API 的一部分
文档不是”开发完的附属品”,而是 API 的使用契约。它的价值:
- 前端自助对接:不用每次来问你”这个字段叫啥、必填吗”,看文档自己调。
- 测试和调用方受益:测试同学按文档写用例;第三方开发者按文档集成。
- 减少扯皮:联调出问题,先翻文档看”到底谁没按约定来”。
- 新人上手快:接手项目先读文档,比读源码快十倍。
一句扎心的话:没有文档的 API,等于不存在的 API——别人不知道、不敢调、调错怪你。
OpenAPI:文档的”通用语言”
OpenAPI(前身是 Swagger 规范)是一套描述 REST API 的标准格式,用 YAML 或 JSON 写,能精确表达:有哪些路径、每个路径支持什么方法、参数长啥样、请求响应什么结构、返回什么状态码。
一个最小的 OpenAPI 片段:
openapi: 3.0.3
info:
title: 用户服务 API
version: 1.0.0
paths:
/users/{id}:
get:
summary: 获取用户详情
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
别被长度吓到——你几乎不用手写这个。现代框架(如 SpringDoc、FastAPI、gin-swagger)能从代码/注释自动生成它。理解它的结构,是为了知道”文档里该有哪些信息”。
Swagger UI:文档即调试台
光有 YAML 文件还不够直观。把 OpenAPI 描述喂给 Swagger UI,它会自动渲染成一个漂亮的网页:左边列接口、右边能直接填参数、点”Try it out”就发请求看真实响应。
这意味着:文档不再是静态说明,而是可交互的调试台。前端、测试、调用方都能在浏览器里直接试接口,不用自己拼 curl。这对联调效率是质的提升。
常见做法:
- 开发/测试环境挂一个
/swagger或/docs页面,团队随时访问。 - 生产环境务必关掉或加鉴权——你不想把内部接口结构暴露给外人。
三种写文档的方式
根据团队习惯,有三种生成路径:
- 代码注解生成(最推荐):在控制器/路由上写注释,工具扫描后自动产出 OpenAPI。好处是”代码改了文档自动跟”,不会脱节。
// @Summary 获取用户详情 // @Param id path int true "用户ID" // @Success 200 {object} User // @Router /users/{id} [get] func GetUser(w http.ResponseWriter, r *http.Request) { ... } - 手写 OpenAPI 文件:适合先设计后开发(API-First),用编辑器校验格式,再照着实现。大厂协作常用。
- 从代码反射生成:框架(如 FastAPI)靠类型注解直接推导出入参结构,几乎零额外工作。
新手建议从”注解生成”起步:把写文档变成写注释的一部分,成本最低、最不容易过期。
文档里必须有的信息
一份能用的文档,每个接口至少交代清楚:
- 路径与方法:
GET /users/{id}。 - 鉴权方式:要不要带 token、放哪(Header/Query)。
- 请求参数:路径参数、查询参数、body 字段,每个的类型、是否必填、示例值、含义。
- 响应结构:成功返回什么字段、各字段类型;不同状态码(如 400/404/500)分别对应什么。
- 示例:一个完整的请求示例 + 响应示例,比千言万语都管用。
特别注意:必填字段、字段类型、枚举值这三样最容易出错也最该写清。前端按”以为的类型”解析,结果后端返回的是字符串而不是数字,联调当场翻车。
版本与变更管理
接口会演进,文档也要跟着版本走:
- 文档里标
version,和 API 版本(如/v1)对应。 - 破坏性变更(删字段、改字段名、改类型)必须升大版本,并在文档里标注”v1 将于某日期废弃”。
- 非破坏性变更(加字段、加可选参数)可在同版本内更新,老调用方不受影响。
- 维护一个”变更日志(Changelog)“,记录每次改了啥,调用方心里有底。
常见新手坑
- 文档和代码脱节:手写文档后改了代码忘了更,前端照旧文档调,全错。解法:用注解/反射自动生成,让文档跟着代码走。
- 生产环境暴露 Swagger:内部接口结构全公开,安全隐患。生产关掉或加权限。
- 只写成功响应,不写错误:前端不知道 400/404 长啥样,错误处理只能瞎猜。把错误响应也写进文档。
- 缺示例值:光说”返回 User 对象”,前端不知道
status是 0/1 还是字符串。给示例最直观。 - 字段含义不写:
type字段是干嘛的?不写清楚,调用方只能猜,猜错就 bug。 - 必填项不标:前端以为可选没传,后端报错,来回扯皮。
实战:用注解给一个接口写文档
以 gin-swagger 风格注释为例,描述”创建用户”:
// @Summary 创建用户
// @Description 接收用户名和年龄,创建后返回新用户
// @Tags users
// @Accept json
// @Param body body User true "用户信息"
// @Success 201 {object} User "创建成功"
// @Failure 422 {object} ErrorResp "参数校验失败"
// @Router /users [post]
func CreateUser(c *gin.Context) { ... }
运行 swag init 后,工具扫描这些注释,生成 docs/ 下的 OpenAPI 文件,再挂上 Swagger UI,浏览器打开就能看到可交互文档。你写的注释,既是代码说明,又是文档来源——一份投入,两份产出。
新手怎么把文档习惯养出来
文档习惯是”越早养越省事”。建议从第一个接口开始就用注解写文档,把”写接口 = 写文档”刻进肌肉记忆。每天一个小练习:给你昨天写的任意一个接口补上 OpenAPI 注释,并本地起 Swagger UI 看它渲染出来对不对。
另一个心法:把文档当成给”未来的自己”和”队友”的信。你三个月后回头看自己写的接口,大概率也不记得当时为什么这么设计。文档就是那时候的救命稻草。写的时候多一句”这个字段为什么必填""这个状态码什么场景出现”,未来的你会感谢现在的你。
还有,推动团队”文档评审”文化。API 设计评审时,把文档(而非代码)作为讨论对象——因为文档是契约,契约定了,前后端可以并行开发(前端用 Mock 数据,后端按契约实现)。这就是 API-First 开发模式的精髓:先定契约,再各自实现,最后集成,效率远高于”后端写完了前端才看”。
小测验:看看你掌握了没
- 问题一:为什么推荐”注解生成”文档而不是手写?答案:代码改了文档自动跟,不会脱节;写注释即写文档,成本最低。
- 问题二:Swagger UI 的核心价值是什么?答案:把静态文档变成可交互调试台,前端/测试/调用方能直接在浏览器试接口。
- 问题三:生产环境该怎么处理 Swagger 页面?答案:关掉或加鉴权,避免内部接口结构外泄。
这一篇你该记住的
- 文档是 API 的使用契约,没有文档等于接口不存在。
- OpenAPI 是描述 REST API 的标准格式;Swagger UI 把它渲染成可交互调试台。
- 推荐”代码注解生成”文档,让文档跟着代码走、永不脱节。
- 每个接口文档必备:路径方法、鉴权、参数(类型/必填/示例)、响应结构、错误码、示例。
- 破坏性变更升大版本并标注废弃计划;维护 Changelog。
- 生产环境关掉或保护 Swagger;把文档当给队友和未来的信。
到这里,API 设计的”基础 → 资源 → 认证 → 响应 → 文档”五篇走完。下一步可深入限流、缓存、幂等性、灰度发布等高级主题,把接口做成真正扛得住生产流量的服务。