乐于分享
好东西不私藏

API 文档没人看了,问题出在哪?

本文最后更新于2026-07-27,某些文章具有时效性,若有错误或已失效,请在下方留言或联系老夜

API 文档没人看了,问题出在哪?

API 文档没人看了,问题出在哪?

团队七个人、四款 AI 工具、代码风格对不上——CLAUDE.md 来救你

封面

一个创业公司的 CTO 跟我抱怨:他们的 API 文档已经没人看了。

三十多个微服务,上千个接口,每个服务都有自己的风格。有的用 REST,有的用 GraphQL,有的干脆直接暴露数据库端口。接口字段的命名五花八门——同名不同义、同义不同名的情况到处都是。

他说:这些都是 AI 生成的。

团队七个人,前端用 Cursor,后端用 Copilot,还有两个人在用 Claude Code。每个人的 AI 配置不同、习惯不同、对项目的理解不同。前端 AI 按自己习惯生成 camelCase 字段的调用代码,后端 AI 按自己理解返回了 snake_case。一个模块的接口用 /users/:id,另一个用 /getUserById。结果就是各写各的,联调的时候发现对不上。

他说:我知道问题出在 AI 没统一。

我说:问题不在 AI,在你们没有定契约。

问题场景


接口是系统之间的语言

接口的本质是契约。它在系统之间划了一条线——线的这边是我的责任,那边是你的。接口定义了双方各自负责什么。

这条线最容易出问题的地方不在技术层面,在认知层面。后端说”我返回了用户数据”,前端一看多了二十个用不上的字段。前端说”我要用户数据”,后端不知道他需要的是用户的基本信息还是完整资料还是只用于展示的头像和昵称。

这些模糊地带在代码里不会报错,但它会导致一系列连锁反应。

前端自己拼数据。 用户列表调一次,用户详情又调一次,为了凑齐一个页面要调五六个接口。用户等得烦躁,前端写得痛苦。每次需求变更都要改一堆调用逻辑。

字段膨胀。 因为不确定别人用不用,就都返回。一个接口从 5 个字段膨胀到 30 个字段,最后连开发者自己都不知道哪些字段还在被使用。删又不敢删,留着又恶心。

隐式依赖。 前端依赖了一个后端没承诺会稳定的字段。半年后后端重构数据库,字段没了,前端页面直接崩溃。这种事故排查起来极其痛苦——因为没有任何文档记录这个依赖关系。

更麻烦的是,AI 生成接口的时候默认”多返回”。它不知道哪些字段是内部使用的、哪些是外部需要的。你让它”返回用户信息”,它就把用户表的所有字段都给你——包括 passwordhash 和 internalnotes。

我见过一个真实案例。AI 生成的用户详情接口返回了 47 个字段,其中 12 个是内部系统用的,8 个包含敏感信息。前端开发者为了方便,直接把整个返回对象存进了 localStorage。结果用户的角色权限、内部备注、甚至密码修改时间戳都暴露在了浏览器里。

还有一个更隐蔽的问题:接口语义的漂移。同一个 “GET /users/:id” 接口,三个月前返回的是基本信息,现在因为某个新需求加了十几个字段。调用方不知道这些字段是新加的,也不确定它们是否稳定。于是每个人都只挑自己认识的那几个字段用,新加的字段没人敢碰——因为没人知道它们会不会明天又变了。

这种语义漂移在 AI 生成的代码库里特别常见。AI 不会考虑”加这个字段会不会破坏已有的契约”,它只会按你的 prompt 实现当前需求。


好的契约长什么样

好的接口契约不需要复杂的规范和工具。几个简单的原则就能让接口质量大幅提升。

契约原则

字段明确,不塞多余信息。

每个接口只返回调用方需要的数据。这个原则看起来简单,实际执行很难。因为”多返回几个字段又不会错”是人的本能——省得以后还要再加。但多返回的每一个字段都是隐式的依赖。调用方一旦用上了,你就不能随便改。

一个接口从 5 个字段膨胀到 30 个字段,就是这么来的。怎么避免?在写接口定义的时候问自己:这个字段是调用方必须知道的吗?不是就删掉。不确定?先不返回,等有人要再加。加字段容易,删字段难。

版本策略提前定。

接口迟早要变。提前想好版本策略:是加字段不加版本、改字段升版本、还是直接用新接口替代旧接口。不管选哪种,定下来就不要改。

最怕的是每次变接口都临时决定版本策略。结果有的加版本号、有的加请求头、有的靠文档通知。调用方根本不知道你的规则是什么,每次对接都要重新学一遍。

AI 不会帮你决定这些——你告诉它用哪种策略,它就做哪种。你不说,它就按自己的理解来。今天用 v1,明天用 2023-01-01,后天干脆不加版本。

错误信息对人对机器都有用。

大部分接口的错误处理是”返回 500,啥也不说”。好的错误处理告诉调用方:什么错了、为什么错、怎么改。

三段式错误:HTTP 状态码表示错误类别,业务错误码表示具体的错误,错误消息用人类能读的语言描述。比如:

400 Bad Request{  "code": "INVALID_PHONE_FORMAT",  "message": "手机号格式不正确,应为 11 位数字"}

AI 默认的错误处理很差——它倾向于抛出一个通用异常。你需要告诉它:每一个可能的错误路径,都要有明确的错误信息。空参数怎么返回?权限不足怎么返回?资源不存在怎么返回?一个一个列清楚。

接口粒度适中。

太粗的接口——一个接口返回整个系统的数据,前端从里面挑自己需要的——造成网络浪费和耦合。太细的接口——获取用户名一个接口、获取用户头像一个接口——造成请求爆炸。

一个标准:按业务场景聚合。用户详情页需要什么数据,就提供一个接口返回这些数据。不要为了让接口”通用”而把所有数据都塞进去。

AI 倾向于把接口做得极细——因为它不知道哪些数据经常一起使用。你需要在设计阶段就定义好:这个页面需要哪些数据,它们应该来自几个接口。


常见误区

误区一:先写代码,再补接口文档。

这是最普遍的坏习惯。代码写完了,接口已经定了型,文档只是对已有实现的描述。这时候文档已经没有约束力了——它只是解释了代码做了什么,而不是规定了代码应该做什么。

正确的顺序是:先写接口契约,再写实现。契约是双方协商的结果,实现是契约的落地。AI 也很擅长根据契约生成实现代码,但你得先把契约给它。

误区二:一个接口服务所有场景。

“我们做个通用接口,谁要什么数据自己挑”。听起来很美好,实际上很灾难。不同场景的字段需求不同,性能要求不同,权限要求也不同。一个接口想满足所有人,最后谁都不满意。

更好的做法是为不同场景设计不同接口。展示用的接口返回精简数据,管理后台用的接口返回完整数据,导出用的接口返回特定字段。重复一点代码没关系,接口的清晰和稳定更重要。

误区三:接口变更靠口头通知。

“这个字段不用了,大家改一下”。微信群发一条消息,以为所有人都收到了。实际上总有遗漏——新加入的同事不知道,外包团队没看到这个群,某个定时任务还在依赖这个字段。

接口变更必须走正式流程:文档更新、版本发布、变更通知、迁移期限。这个流程不能靠人,要靠工具和自动化。


关键解法:CLAUDE.md 统一 AI 的行为

上面说的这些问题,在一个人的项目里已经够头疼了。但真正让局面失控的,是每个开发者用的 AI 都不一样——前端 AI 以为项目用 camelCase,后端 AI 以为用 snake_case,还有个 AI 压根没被告诉过项目的命名规则。

每个 AI 单独看都写得不错。问题是每个 AI 看到的上下文不一样。Cursor 知道你这部分代码,不知道隔壁模块的约定。Copilot 根据当前文件的代码推测风格,但如果当前文件本身是新写的、没有历史参考,它就按自己的默认习惯来。Claude Code 的上下文取决于你给了它什么 prompt——prompt 里没说字段命名规则,它就按训练数据里的统计偏好来。

结果就是:项目里的代码风格不是一个人决定的,也不是一群人商量决定的——是每个人各自的 AI 在各自的小上下文里随机决定的。

解法不是让所有人在同一台电脑上写代码,也不是禁用 AI。解法是给所有 AI 一份共享的项目规范。

CLAUDE.md 解法

这份规范就是 CLAUDE.md。

CLAUDE.md 放在项目根目录,它是一份纯文本的约束文件,主要作用是告诉 AI 这个项目是怎么做的。主流 AI 工具——Cursor、Copilot、Claude Code、WindSurf——都会自动读取它。你不需要在每个 prompt 里重复项目规范,AI 自己会去看。

CLAUDE.md 里写什么?

  • 命名约定:字段用 camelCase 还是 snake_case,路径用 /users/:id 还是 /user/:id
  • 接口规则:版本策略、错误格式、认证方式
  • 代码风格:用什么框架、文件怎么组织、测试怎么写
  • 技术选型:用了哪些库、版本要求、构建工具
  • 关键约束:不能做什么、必须做什么

一个简单的例子:

# API 规范## 命名- 接口路径用 kebab-case:/user-profiles/:id- JSON 字段用 camelCase:userId, createdAt- 枚举值用 UPPER_SNAKE_CASE:ADMIN, USER## 分页- 每页默认 20 条,最大 100 条- 请求参数:page, pageSize- 响应:{ items: [], total: number, page: number, pageSize: number }## 错误- 格式:{ code: string, message: string }- 400 参数错误,401 未认证,403 无权限,404 不存在,500 服务端错误

关键是:这份文件既是给人看的,也是给 AI 看的。团队评审的时候按这个标准,AI 生成代码的时候也按这个标准。两边对齐了,AI 才不会跑偏。

你不需要一次写完——先定几条关键规则放进去,跑一阵发现问题再补充。但一定要有。只要没有 CLAUDE.md,每个 AI 就按自己的理解来。有了它,所有 AI 都在同一份约束下工作,写出来的东西才像一个人写的。


实操建议

用 CLAUDE.md 约束接口风格。

在上面的关键解法里已经说了 CLAUDE.md 的作用。具体到接口层面,CLAUDE.md 需要写清楚:

  • 命名风格(camelCase 还是 snake_case)
  • 路径规则(/users/:id 还是 /user/:id)
  • 版本策略(URL 路径版本还是请求头版本)
  • 错误格式(三段式还是两段式)

不需要多复杂,一页纸就够了。关键是让这份规范成为所有 AI 的共同上下文。

用 OpenAPI 或类似的工具定义接口。

人写 YAML,AI 读 YAML 生成代码。这样接口定义和实现天然对齐。AI 也能根据定义生成客户端 SDK 和测试代码,一举多得。

建立接口评审机制。

不是代码评审,是接口评审。在新接口开发之前,让前后端一起过一遍接口设计。这个评审关注的是:字段命名是否清晰、返回结构是否合理、错误处理是否完善。花 15 分钟评审,省下一周的返工时间。

接口评审的一个实用技巧:让前端用 mock 数据先写页面,后端根据 mock 定接口。这样双方对”这个数据长什么样”有了共同理解,AI 生成代码的时候就不会跑偏。


让 AI 写接口之前,先把规格定好

AI 很擅长根据接口定义生成实现代码。你给它一个 OpenAPI 规范,它能生成完整的服务端代码和客户端 SDK。

问题在于:谁来定义这个规范?

如果把定义权交给 AI——让 AI 决定接口叫什么、参数怎么传、数据怎么返回——那不同模块之间的一致性就是看运气。今天 AI 生成用户服务的接口用 userId,明天生成订单服务的接口用 user_id。两个服务之间要对齐?手动改吧。

更好的做法是:人定接口规范,AI 做实现。人在设计阶段决定:这个模块对外暴露什么能力、接口的粒度和命名风格是什么、版本策略怎么处理、错误怎么返回。把这些写入 CLAUDE.md 或 OpenAPI 文件。AI 在实现阶段把这些设计变成代码。

这样分工:人做判断——”为什么这么做”和”做成什么样”。AI 做执行——”怎么实现”。接口设计这件事上,判断比实现值钱得多。因为接口设计错误的影响范围是整个系统的所有调用方。而实现错了,重写就好。

接口设计是长期的成本。今天省下的十分钟,半年后可能要花十个小时来还。一个设计糟糕的接口,后续每个迭代都要处理兼容性问题——而 AI 生成的代码越多,依赖这个接口的调用方就越多,修改成本就越高。

收尾


这是《AI 时代程序员新技能体系》30 篇系列的第 8 篇。

下一篇(第 9 篇):你还在用老方法审查 AI 代码吗?

每天一篇,一个月完成一轮系统升级。关注这个系列,不要错过下一篇。