API Schema Diff 上线前评审:oasdiff / graphql-inspector 实战

API Schema Diff 上线前评审:oasdiff / graphql-inspector 实战
Spec Coding 编辑部 · Spec-First 工程实践内容

上线前如何做 API schema diff 评审:自动化 diff 工具能抓到什么、漏掉什么,以及 OpenAPI 和 GraphQL 仍然需要人工检查的那些点。

发布于 2026-03-10 · ✓ 已更新 2026-05-06 · 阅读约 8 分钟 · 作者:Spec Coding 编辑部 · 审校:编辑与事实核查政策

现场笔记:schema diff 只是警报

diff 会告诉我字段变了,但不会告诉我哪个客户端把字段当成必填,哪个生成 SDK 把 enum 当成封闭集合,哪个报表依赖旧的 null 行为。diff 亮起来之后,评审才真正开始。

Diff 评审行:
变更:新增 enum 值 refund_status=pending_review
Schema 分类:新增
调用方风险:移动端生成客户端用了 exhaustive switch
必须证据:移动端契约测试覆盖未知 enum
发布说明:指定日期前需要客户端动作

那次我差点放行的 diff

几个版本之前,我眼睁睁看着一行 schema 变更让三个移动端客户端挂了四十分钟。字段是 order.total,之前一直是整数。后端做了一次重构,把它改成字符串,这样就能返回精确的小数金额。CI 流水线跑了 oasdiff,类型变更被标了出来,评审人勾上了 breaking-change 标签,然后一句"客户端会处理的"就批了。结果他们没处理。iOS 用 Int.init 解析,拿到的是 nil,购物车页面显示为零。整个评审过程里,没有人真的去看一个真实的客户端调用点。

我现在还是会在每次发布都跑 schema diff,只是它不再是我最信任的那一环。

oasdiff 和 graphql-inspector 真正能抓到什么

自动化 diff 对结构性变更相当擅长,我希望它在每个 PR 上都跑。实际用下来,oasdiff 跑 OpenAPI、graphql-inspector 跑 SDL,可以稳定告诉我这些事:

这些"容易犯的错"它都能兜住。有人不小心删了一个 endpoint,diff 会吼;悄悄加了一个必填 query 参数,diff 也会吼。挺好,留着。

Diff 工具悄悄漏掉的东西

让我栽过跟头的是另一类情况:schema 看起来一模一样,底下的行为却已经翻面了。Diff 工具是个语法级的仪器,下面这些它一个也看不到:

每个 diff 都能归到三类里

我要求评审人把每个变更归到三堆之一。工具给出第一遍分类,最终判断永远由人来做。

第三类的意义是防止评审人麻木。如果每个 diff 都吓人,那就等于没有哪个 diff 真吓人。把无害的那些显式标出来,真正危险的才会被认真对待。

我的评审清单,按顺序来

每次审 schema 变更的 PR 之前,我都会对着同样的五个问题走一遍:

用 Given / When / Then 写验收标准

每次新增或修改一个契约,我会在动 schema 之前先把期望行为写成一个场景。这种做法逼我去注意到 diff 抓不到的语义漂移。

- Given a client on v2.3 of the orders API
  When it requests GET /orders/{id} for a refunded order
  Then the response returns 200 with status="REFUNDED"
    And clients written before REFUNDED existed receive an enum value
      they do not recognize and must fall back to "UNKNOWN"

- Given an integration using the 409 response to trigger a duplicate-submit dialog
  When optimistic lock contention also returns 409
  Then the release notes flag the overloaded meaning
    And a new error code is introduced instead of reusing 409

评审结束之后真正留下来的是这个场景。Diff 只是提醒我"场景该写了"的闹钟。

我实际在用的 CI 门禁

流水线里就两条规则,不多:

有一件事我故意不做:自动批准非 breaking 的变更。工具还没聪明到能替我下这个判断。评审人依旧会看每一份 diff,因为 nullability 和枚举这两个陷阱恰好就住在"非 breaking"那一格里。

和版本策略怎么接上

Schema diff 评审是你所选版本策略的证据来源。跑 semver?"breaking"那一堆决定 major 还是 minor。跑基于日期的版本加弃用窗口?diff 告诉你弃用窗口什么时候开始计时。跑单一 evergreen 版本?diff 就是你每周向自己证明"确实向后兼容"的那份依据。还有一条很实在的规则:能避免就不要在同一个 release 里同时发 breaking 和非 breaking 的变更。把 breaking 变更单独放出去,沟通更清晰,回滚也更容易。

那次 integer 变 string 的事故之后我改了什么

Diff 工具本身没问题,是人没审到位。我后来改了自己的流程:

这些做法一点都不花哨,但任何一条放在当时,都能在 order.total 那次变更到达手机之前把它拦下来。

评审时看什么

这篇文章适合用在API schema diff 上线前评审时。别从“原则”聊起,直接拿一条真实改动来对照,看看规格里还缺什么。

diff 报告只是入口。最后要写进发布说明的是:哪些变更允许上线,哪些必须延期或升版本。

Schema diff 后面还要有人读语义

自动 diff 能告诉你字段删了没有、类型窄了没有,却看不出“含义悄悄变了”。我会让 reviewer 在 diff 结果下面补一段人工判断,尤其是默认值、枚举、分页和错误语义。

Human semantic review:
- Field added: customer.tier, nullable, default absent
- Risk: mobile client may sort unknown tier after paid tiers
- Fixture added: old client receives tier=null and renders "standard"
- Error shape: unchanged
- Pagination: cursor remains opaque, no ordering promise added
- Decision: safe additive release, monitor client parse errors for 48h

边界:不要把 schema diff 当成发布批准。它只是第一关。涉及语义、计费、权限或排序规则的变化,即使 diff 显示“非破坏”,也要人读。

我会额外检查缓存和分页

schema diff 很少提醒你缓存 key、分页 cursor 和默认排序。只要 API 返回列表,就要写明新增字段是否进入缓存,状态变化是否影响排序,旧 cursor 在发布后是否还能继续翻页。测试证据最好包含一组发布前生成的 cursor。

可复制产物:契约评审包

当工作涉及 API 行为、schema、事件、重试或消费者预期时使用。它会把兼容性和发布证据提前摊开。

API 契约评审包:API Schema Diff 上线前评审:oasdiff / graphql-inspector 实战

本次要做的决策:
- 确认契约变化是否兼容,消费者需要什么迁移动作,发布后如何观察风险。

责任人检查:
- 产品责任人:
- 工程责任人:
- QA 或运维评审:

范围边界:
- 本次包含:
- 本次不包含:
- 仍需确认的假设:

验收证据:
- 测试或 fixture:
- 日志、指标或截图:
- 人工复核步骤:

契约边界:没有兼容性分类、消费者影响、重试行为和回滚说明,不进入发布。

评审追问:
- 没参加需求会的人还会误解哪里?
- 哪个证据能证明这次改动足够安全,可以发布?

旗舰使用路径

这是 Spec Coding 用来承接「API Schema 发布评审」主题的核心参考页之一。建议把它放到真实工单、PR 或发布评审里使用,而不是只当背景文章阅读。

旗舰页使用路径:
- 在计划或评审时打开本文。
- 把对应产物复制到工单或 PR。
- 用自己的系统、责任人和失败模式替换示例值。
- 如果证据行仍为空,就不要进入实现。

二次审阅记录:分类行为,而不只是形状

这次检查的重点是避免文章像泛泛 API 清单。新增评审语言更聚焦调用方影响和发布证据。

Schema 评审决策:
- 安全:旧调用方会忽略,或已有测试证明可容忍。
- 有风险:旧调用方可能解析、排序、缓存或 switch 它。
- 破坏性:旧调用方不改代码会失败或行为错误。
- 未知:调用方列表或代表性测试缺失。

编辑复核记录

复核日期:2026-04-29。本次补充了可复用产物,按相关主题 Hub 检查了文章定位,并收紧下一步链接,让页面更像可操作参考,而不是孤立长文。

关键词:API schema diff、oasdiff、graphql-inspector、breaking change 评审、OpenAPI 版本策略、GraphQL schema 评审、发布门禁、向后兼容

专题阅读路径

这篇文章归入 API 契约 主题。先读 Hub,再结合下面的清单、模板或工具落到具体项目里。

编辑说明与免责声明

最近复核:2026-04-29。编辑部检查了示例、内链和可复制评审片段,确保内容更适合真实项目使用。

本文用于软件工程教学与实践参考,不构成法律、税务或投资建议。示例场景用于解释规格方法,不对应真实客户数据。