OpenAPI Diff
所谓 OpenAPI 对比,就是比较同一 API 规范的两个版本——旧契约与新契约——并报告到底变了什么:端点被删除、参数变成必填、字段类型发生变化、枚举值消失。在下方载入或粘贴两份规范,本页面会把每一项变更分类为破坏性或非破坏性,让你在供应商升级或自己的版本发布进入生产之前先作出判断。两个文件都在本页面、你的设备上解析——不会上传任何内容,这很重要,因为规范里往往描述了你不想放在别人服务器上的内部端点。不熟悉这些术语?配套文章 破坏性 API 变更详解 定义了这里用到的每一个概念。
最后更新:
旧规范(客户端今天正在使用的契约)
将文件拖到此面板任意位置、选择文件,或粘贴文本。解析在本机进行;不会有任何内容离开这台设备。
新规范(候选契约)
将文件拖到此面板任意位置、选择文件,或粘贴文本。解析在本机进行;不会有任何内容离开这台设备。
比较结果
摘要已复制到剪贴板。
这个对比工具检查什么——以及“破坏性”到底是什么意思
一项变更之所以是破坏性的,是因为一个严格按旧规范写对的客户端,不改自己一行代码,就可能在新规范下失败。页面上的每一个判断都由这个定义驱动。删除路径或操作是破坏性的,因为现有的调用无处可去。删除响应状态码——尤其是 2xx——是破坏性的,因为客户端的错误处理正是围绕旧的状态码集合编写的。新增一个必填参数或必填的请求属性是破坏性的,因为昨天的合法请求会突然被拒绝。改变字段的类型或格式是破坏性的,因为解析器、校验器和生成的 SDK 都按声明的类型工作。移除枚举值是破坏性的,因为客户端可能仍会发送它,或者保存着无法再解释的数据。其余一切——新端点、可选参数、新的响应字段、新的枚举值、新的状态码——都被报告为非破坏性:旧客户端继续可用,哪怕它暂时还用不上新能力。
比较是结构层面的,不是文本层面的。在比较之前,两份文档都会被归一化为同一个模型:每条路径和每个操作、按名称与位置索引的参数、请求正文与每个响应都被归约为一个模式签名——由类型、格式、属性名、必填列表和枚举值递归构建的确定性摘要,本地 $ref 引用会被展开。正因如此,调整键的顺序、重排空白或重写所有描述文字都会得到一个空的对比结果:这些都不改变契约。也正因如此,埋在被引用模式三层深处的一处变更仍然会被找到——签名展开的是引用本身,而不是仅仅比较它的名字。
这里接受两种输入形态,因为生态里两种都有人发布:先按 JSON 尝试解析,失败时再按 YAML 解析——大多数手写的 OpenAPI 文档用的正是 YAML。Swagger 2.0 文档同样可用,包括它的 in: body 参数和每个响应自带的模式。这里刻意没有在线拉取、也没有上传:像处理 HAR 抓取文件 一样粘贴文档或拖入文件即可,而且对比是在你按下按钮时才运行——而不是每次按键都运行——所以粘贴两份很大的规范也不会卡顿。
把结果当作发布门禁来用,而不是装饰。在评审中,破坏性列表就是议程:每一项都需要修复、提升版本号、给出弃用窗口,或者留下一份“这次破坏是有意为之且已通知”的书面决定。非破坏性列表就是变更日志的草稿。把对比结果导出为 JSON,可以把这份决定归档在版本旁边;可复制的摘要可以直接放进拉取请求——这与对待 webhook 契约变更是同一套纪律:一份被悄悄改动的负载会同时破坏每一个订阅方。
诚实的限制,明确说出来。这个对比工具比较的是声明过的契约:它看不见规范没有声明的行为,例如字段类型不变但含义变了、新增的业务规则、更紧的限流,或者客户端(不明智地)在解析的错误消息文本。工具会跟随本地引用并在有限深度内比较模式,因此病态的深层嵌套或互相递归的模式会被摘要化,而不是无限展开下去。而且,零破坏性变更的对比结果并不能保证升级一定安全——它证明的是文档化的契约没有变,这恰恰是部署之前值得拥有的证据。
本页据以评判的分类表
| 删除路径或操作 | 破坏性。对一个已不存在的端点的调用会直接失败;没有任何兼容方式能让旧客户端继续对着它工作。 |
| 删除响应状态码 | 破坏性。客户端的重试、错误处理和监控逻辑都是围绕声明过的状态码集合编写的;丢失一个 2xx 是其中最严重的形式。 |
| 参数变为必填 / 新增必填字段 | 破坏性。在旧规范下合法的请求会被新规范拒绝,因此每个现有客户端都必须先做出修改才能调用该端点。 |
| 类型或格式变更 | 破坏性。解析器、校验器和生成的 SDK 都是按声明的类型构建的;integer 改成 string(或 int32 改成 int64)会破坏严格的客户端,哪怕线上值看起来很相似。 |
| 删除属性(请求或响应) | 破坏性。客户端发送的请求属性会被忽略或拒绝;客户端读取的响应属性会在它的代码里变成空值或缺失。 |
| 移除枚举值 | 破坏性。客户端可能仍会发送被移除的值,或者保存着使用该值的数据。新增的枚举值是非破坏性的,会被单独报告。 |
| 新增内容 | 非破坏性。新的路径、操作、可选参数、可选的请求属性、响应属性、响应状态码和枚举值,永远不会让一次先前合法的交互失效。 |
常见问题
我的规范文件会被上传到任何地方吗?
不会。两份文档都在本页面、你的设备上解析和比较;比较过程不会发出任何网络请求,也不会存储任何内容。这是一条刻意定下的规则:规范就是一份 API 的地图——包括内部的和未公开文档的端点——一个要求你先上传它才能对比的工具,收集的恰恰是你应该保密的那张地图。
接受哪些格式?
OpenAPI 3.x 和 Swagger 2.0,JSON 或 YAML 均可。文本先按 JSON 尝试,失败时按 YAML 解析。文档必须带有 paths 对象才会被识别为规范;其他内容会被报告为“不是规范”,而不是悄悄给出一个空的对比结果。
这里什么算破坏性变更?
任何可能让一个写对的旧客户端失败的变更:删除路径、操作或响应状态码;参数或请求属性变为必填;类型或格式变更;删除请求或响应属性;以及移除枚举值。新增任何可选内容都是非破坏性的。描述、标题和格式变化会被完全忽略——它们不是契约变更。
被引用的模式如何处理?
构建签名时,#/components/schemas/Pet 这类本地引用(或 Swagger 2.0 中的 #/definitions/Pet)会被解析,因此一份共享模式内部的变更会在每个使用它的操作上被报告。解析有深度上限且能安全处理循环,递归模式不会让比较卡死。
我可以归档或分享结果吗?
可以。下载按钮把完整的对比结果导出为 JSON——摘要计数加上每一项变更的严重级别、种类、路径、方法和结构化细节;复制按钮生成适合放进拉取请求或发布说明的纯文本摘要。两者都是在本机从你刚运行的对比结果生成的。