Cursor 写完接口请求,还要过契约校验
AI 生成的请求即使能返回数据,也可能在路径、方法、请求头或请求体上偏离 API 契约。文章建议结合定义检查、模拟服务或契约测试,验证生成请求及其边界情况。
AI 深度解读
Cursor 生成的请求在编辑器里看着顺眼,运行后也拿到了数据,就能合并了吗?作者的答案是:还不够。一次 200 只能证明某个输入碰巧走通,不能证明请求符合 API 契约,尤其覆盖不了字段改名、类型错误,以及可选字段和 null 的边界。
作者给出的办法是把 OpenAPI 当作校验依据,先检查请求定义,再通过契约驱动的 mock 执行请求,最后接入 CI。这套思路值得读,但原文没有工具配置、可运行示例或对照数据,需要区分工程原则和已经验证的效果。
为什么拿到 200,还不能证明请求写对了
AI 编程助手擅长快速补出 fetch 调用、客户端初始化,甚至重试逻辑。问题在于,生成代码的语法完整程度,并不能反映每个细节的可靠程度。正确的请求头和猜出来的请求头,看起来可能同样自然。
作者列出的风险包括:字段已经改名,代码仍沿用旧名称;接口要求 number,实际发送的却是 string;请求体只包含一组看似合理的字段,却没有处理可选字段和 null。
这里需要把两个判断分开:
一次调用成功,证明的是某个请求实例能运行;契约校验关注的是请求是否符合接口约定。
例如,某字段允许省略,不代表一定允许传 null。前者是没有提供值,后者是明确提供了空值。如果只测试字段有值的情况,这个差异就不会暴露。作者认为,可选字段和 null 是生成代码经常出错的位置,但没有提供样本数量或统计结果。
OpenAPI 的作用,就是给这些判断提供代码之外的依据。路径、HTTP 方法、请求头和请求体结构,都应该与契约核对,不能只凭周围代码和自然语言描述推断。
怎样把契约检查变成能反复执行的流程
作者建议分两步:先用 linter 检查请求定义,再把请求放进契约驱动的 mock 或测试环境中执行。
第一步检查请求定义是否符合 schema。第二步实际运行请求,并验证路径、方法、请求头和请求体,同时让 mock 返回契约声明的响应,覆盖成功和错误分支。
两步解决的问题不同。定义检查关注结构是否合法;执行检查则需要观察代码真正发出了什么,以及收到响应后走到了哪个分支。对于前端请求封装,后者尤其有用,因为最终发送的数据还可能经过序列化或公共请求逻辑处理。
使用 mock 的理由也很具体:共享测试服务的数据和状态会变化,而契约驱动的 mock 更容易稳定复现指定响应,错误分支也不必等真实服务恰好出错才能测试。
但原文没有交代具体 linter、请求定义格式、mock 工具和断言方式。它提出的是验证流程,尚不足以照着配置直接落地。
这里还有一个实现上的关键区别:mock 能返回声明过的响应,不等于它一定会拒绝非法请求。要落实作者的主张,测试环境必须真正检查发出的请求,而不是无论传什么都返回一份成功数据。
为什么检查要跟着每次变更一起跑
即使生成时请求完全正确,契约变化后也可能失效。字段改名、约束收紧,都会让旧代码逐渐偏离约定。
作者因此主张把校验接入测试套件和 CI,让每次变更都重新检查。这样,团队不必记录哪些文件由 AI 生成,手写代码和生成代码都经过同一套门槛。
需要持续验证的是请求与契约的关系,而不是代码的作者身份。
原文还强调本地优先:契约文件和请求定义放在仓库里,验证依赖本地文件,就不必依靠云端工作区。这有利于本地检查和 CI 复用。不过,这说的是契约验证环节,不代表完整应用测试也能脱离真实服务运行。
我的判断
我赞同把 OpenAPI 从参考文档变成自动检查的依据。相比只审查生成代码,或手动点一次页面确认有数据,这种做法能把字段类型、请求头和边界输入变成明确的检查项,也更适合反复执行。
但它依赖一个前提:契约本身可靠。如果 OpenAPI 已经过时,或没有写全约束,通过检查也只能证明代码符合这份文件。契约驱动的 mock 与真实服务是否一致,仍然需要另外验证。
因此,这套流程适合补充真实服务测试。mock 便于稳定覆盖成功、错误和边界分支;真实服务测试则用于发现契约与实现之间的差异。两者承担的任务不同。
原文也没有给出 Cursor 与其他生成方式的错误率对照,没有量化接入后的收益。「可选字段和 null 最常出错」应当视作作者的经验判断。文末提到 Powerduck vs Cursor 系列,但本文没有展开比较,不能据此判断两款产品的优劣。
能拿来做什么
- 让 Cursor 生成前端或 Node 请求代码时,同时提供仓库中的 OpenAPI 文件,并把生成结果继续视为待验证代码。
- 给请求测试补上可选字段省略、显式传 null、字段类型错误和契约声明的错误响应,检查请求及响应处理是否符合约定。
- 检查现有 mock 是否会校验路径、方法、请求头和请求体;如果只是固定返回成功数据,就补上请求断言。
- 把契约检查接入 CI,并在契约变更时重新运行相关请求测试,让手写代码与生成代码接受相同检查。