Apideck 为何放弃 Spectral:API linting 的规则集才是核心资产
What leaving Spectral looked like at Apideck for API linting
Apideck 在 API linting 上放弃 Spectral,转而主张规则集(ruleset)才是真正值得拥有的资产,而非运行它的 linter。Kin Lane 统计 1,005 个在 CI 中运行 Spectral 的公开 GitHub 仓库中,63% 只用默认规则集,13% 设置 continue-on-error 使失败不阻塞。
Linter 是 API 治理真正落地的地方
我合作过的每家公司都有 API 指南,但几乎没人在第一个月之后还去读它。在 Adidas,指南本身没变;改变的是它们开始在流水线中运行的那一天。
这些指南曾躺在 wiki 页面上,有时是一份设计精美的 PDF,还有一次是带目录的整个网站。所有人都认同它们。可 API 还是照样跑偏。Kin Lane 从另一面统计了同样的事:在他进行的 260 次设计评审中,大约只有 15 个团队读过指南。
在 Adidas,我们公开了 API 指南,并在旁边放了一套 Spectral 规则集,把机器能检查的部分编码进去。从那时起,风格指南就成了一个 CI 步骤。当某个团队交付的契约命名不一致、缺少错误 schema,或者有没人愿意描述的端点时,它就会变红。评审者得以争论设计问题,因为构建已经替他们抱怨过 camelCase 了。
只有当你的规则在 CI 中运行时,API 治理才真正落地,而值得拥有的资产是规则集,不是运行它的 linter。
为什么 linter 是你手里最便宜的杠杆
一旦有超过少数几个团队构建 API,这三件事就再次成为 CTO 的问题。
不管你喜不喜欢,你的资产组合就是多语言的。一个团队交付 Java,另一个用 Go,第三个有个没人想碰的 Node 服务。你没法在那么多代码里强制一致性,也没法给每个 pull request 都配一个人类架构师。每个团队以相同格式产出的唯一产物就是 API 描述,通常是 OpenAPI。对它做 lint,你就能治理每个团队,无论背后是什么语言。
评审很昂贵。资深工程师每花一小时去要求复数名词、4xx 响应或参数描述,就少了一小时去处理真正重要的设计问题。规则集把 API 评审中机械的那一半永久地从桌面上拿掉。它还消除了尴尬的对话。没人会像跟同事争论那样跟构建争论。
第三个是新的。编码助手现在会大量编写 API 契约,而它们看似合理的时候远远多于真正正确的时候。助手会发明一种你公司里其他地方都没用过的命名约定,跳过安全方案,然后交给你一份 OpenAPI 文档,它验证得完美无缺,却违反了你所有的规范。每周都有更多契约进入你的仓库,而其中被了解你标准的人读过的却越来越少。CI 中的确定性检查是唯一能随这种数量增长而扩展的关口。
规则集是一个产品,分为五层
大多数声称对 API 做 lint 的公司,运行的都是工具自带的默认规则集。那只是拼写检查。Kin Lane 去测量了一下:在
1,005 个在 CI 中运行 Spectral 的公开 GitHub 仓库中,63% 只使用默认规则集,别的什么都不用。13% 设置了
continue-on-error,所以 lint 失败永远不会阻塞任何东西。
一个名副其实的规则集是分层运作的,每一层都要付出更多努力,也会带来更多回报:
-
有效性。这是一份格式良好的 OpenAPI 文档吗? 每个工具开箱即用都能做到这一点。
-
命名与结构。路径大小写、复数资源、 一致的参数名、版本号放在正确的位置、分页只有一种形态。日常 评审中的大部分噪音都在这里,而这一层 在第一个月就能回本。
-
安全。每个操作都有安全方案, 没有任何东西走明文 HTTP,查询字符串中没有敏感数据。你不必自己写这些。 Stoplight 的 OWASP 规则集 针对 OWASP API Security Top 10 2023,API Commons 维护了一个 包含 22 项检查的版本, 覆盖全部十个类别,而 Vacuum 内置了一个。
-
文档。每个操作和 参数都有描述,每个 schema 都有示例,标签要有意义。写起来很无聊。它也是 一个 API 被采用,还是收到一条 Slack 消息问它怎么用,这两者之间的区别。
-
业务规则。每个金额字段都使用公司的 Money schema。每个列表端点都支持 标准过滤语法。每个事件都携带租户 标识符。这些需要自定义函数,它们 只属于你,而且它们是保护你 实际架构的规则。
如果你想证明规则集能够承载真正的策略, 看看荷兰。政府的 REST API Design Rules 在“遵守或解释”制度下对公共机构具有强制性,而且它们 以 Spectral 规则集的形式发布。该 linter 在规范性文本中被直接点名。
要快速审计你自己的设置,问问你的 规则集止步于哪一层。根据我的经验,大多数止步于两层。 没有人能达到五层,除非把规则集当作一个 产品,配有负责人、测试和变更日志。
拥有规则集,租用运行时
多年来,工具一直是 Spectral,没人因此被解雇。 现在真正重要的决定是规则集格式, 因为格式比运行它的任何东西都更长寿。
Spectral 仍是参考标准。它在 2026 年发布了五个版本,
从 4 月的 6.15.1 到
8 月的 6.16.3,并且 Spectral 的维护者在 9 月 17 日合并了
OpenAPI 3.2 支持。社区方面则是另一番景象。根据
Kin 的统计,维护者在 2021 年关闭了 157 个 issue,2025 年关闭了 12 个,
今年到目前为止关闭了 10 个。有 241 个未关闭的 issue,而且
最古老的未关闭社区 pull request 已经等待了五年。
然后在 6 月 30 日,一个名为“chore:
added scarf telemetry to cli”的 29 行 pull request 让这个 linter
在安装时回传数据。你可以用
scarfSettings.enabled: false 将其关闭。
截至 2026 年 9 月,我对这四个选项的看法:
|
工具 |
它是什么 |
何时选择它 |
需要注意什么 |
|---|---|---|---|
|
Spectral |
参考实现。大多数已发布的 规则集都以它为目标。 |
你运行它,你的自定义函数是 JavaScript, 而且它能用。 |
CI 中的 JavaScript 工具链,自 6 月起的遥测, 停滞的 issue 跟踪器。 |
|
Vacuum |
Go 语言,单一二进制文件,MIT 许可。兼容 Spectral 规则集。支持 OpenAPI 2 到 3.2、AsyncAPI 3、JSON Schema。提供语言服务器、HTML 报告、MCP 服务器。 |
你想要速度,管道中不引入 Node,依赖列表短小。适用于大型规范 monorepo。 |
社区较小。JavaScript 自定义函数采用与 Spectral "非常相似"的设计,因此迁移前请检查函数签名。 |
|
Redocly CLI |
Redocly 平台的一部分。内置规则强大,文档完善。 |
你已经使用 Redocly 发布文档,并希望统一工具链。 |
自有格式。从 Spectral 迁移意味着需要参考迁移指南并重写规则。 |
|
Speakeasy CLI |
一个基于自有 Go OpenAPI 库构建的 linter,围绕 SDK 生成。 |
SDK 生成是你的主要工作流,而 lint 是实现它的手段。 |
自有
|
用 Spectral 兼容的 YAML 格式编写规则,将它们放在独立的仓库中并附带测试,把运行规则的工具视为可替换的。今天由 Vacuum 运行它们。OpenLint 正在设计为明天运行它们。如果改用厂商的原生格式编写规则,那么无论你是否愿意,你都已经绑定了该厂商的路线图。
Apideck 离开 Spectral 的经历
我喜欢 Spectral。在 API 领域,它为我节省的审查时间比任何其他工具都多。我们在 Apideck 仍然弃用了它,原因与规则无关。
问题出在依赖树上。Spectral 引入了大量 JavaScript 包依赖图,每隔几周就有一个出现在漏洞报告中。它们都与 lint 无关。每一个都需要人工查看、决策、升级并重新运行管道。对于一个在 CI 中只负责说 yes 或 no 的工具来说,这是大量的维护工作。再加上遥测,留下的理由就变得很薄弱了。
Vacuum 是一个 Go 二进制文件。我们把它放进流水线, 它读取了我们已有的规则集。迁移 花了几个小时,主要是检查那几个自定义 函数。我们的治理方式没有改变。维护 执行治理的东西的成本几乎 降到了零。
我从中得到的启示:
-
保留规则,替换运行时。
-
先检查你的自定义函数,它们是唯一 不能免费迁移的部分。
-
在下一份漏洞报告到来之前动手。
反对意见:绿勾作秀
对这一切最强烈的反对意见来自我刚刚使用的同一 数据。如果 63% 的流水线使用出厂设置进行 lint, 而 13% 从不阻止,那么大多数所谓的 lint 只是一个绿勾,让每个人都觉得自己受到了治理。 在 Kin 的普查中, 大约一千条流水线中有 2 条 在他的成熟度评分表上得了 8 分中的 6 分。
Kin 更进一步。他把治理称为 一个技术栈:机器规则执行书面政策,一条 指南解释它,而它保护的是消费者 体验。linter 是唯一从外部可见的部分。在他对大规模 治理 API 是什么样子的描述中, 75% 是人的工作。
他说得对,而且情况比普查显示的更糟。 你今天可以通过一次 lint 运行,而它几乎没有触及你文档中的 任何内容,你却永远不会知道。
我的答案是把规则集当作软件来对待:一个负责人, 每条规则一个好例子和一个坏例子作为测试,一个变更日志,以及 一个会阻止的构建。一个没人阅读的 wiki 页面 无法让构建失败。那些 fork Spectral 的人把 覆盖率放进了他们的路线图,这说明他们对待 规则集的方式是一样的。
OpenLint 让格式成为真正的规范
Kin Lane 宣布了这次 fork, 时间是 7 月 29 日,基于 Spectral 6.16.2。核心想法 是把规则集格式从工具中抽离出来。如今它 “由五个与该 linter 运行时耦合的内部 draft-07 元模式 描述”,用 规范仓库的话来说。这次 fork 把它变成一个规范性的 JSON Schema, 拥有自己的版本管理,以及一个任何 linter 都可以 针对其进行测试的一致性测试套件。
在 Stoplight 构建 Spectral 的 Phil Sturgeon 和 Jakub Rożek 已加入,还有 Vacuum 的 Dave Shanley 和 Frank Kilcommins。Mike Kistler 也是。他提交给 Spectral 的 OpenAPI 3.2 拉取请求 带着一个批准审查搁置了六个月,于 9 月 16 日被关闭,维护者第二天就合并了他们自己基于它构建的版本。Kin 说工作组大部分是欧洲人,包括两个国家政府。
这个名字来自一次 社区投票 ,结果打成平手:OpenLint 得 +6,Spectical 得 +6。一次商标检查定了胜负。Kin 的原话: “名字是你交付的第一件合规产物。” 评论区有人 问为什么没人提议 Sporky McSporkface。问得好。
我看了 9 月 23 日第一次办公时间的 录像 。 议程 读起来就像企业一直向 Spectral 索要的清单:模块化规则集、联邦化以便平台团队拥有核心而产品团队扩展它、评分、自动修复、覆盖层,以及行业规则集(通话中提到了 FHIR 和 PSD2)。该小组把覆盖率一分为二:你的测试覆盖了规则集的多少,以及你的规则触及了文档的多少。Kin 想要一种每个 linter 都运行的规则集格式,这样谁都不用迁移。Vacuum 可能成为同一标准的 Go 实现。
会议纪要 把家安在 Open Source Europe,出于“主权原因”,资金通过 Open Collective,Spectral 的 Apache-2.0 许可证延续。代码从一个带有 Spectral 完整历史的全新仓库开始,而不是 GitHub fork,这样修复可以双向 cherry-pick。移除遥测和供应链健康在清单上,这是我们离开原因的礼貌说法。AI 使用极少,且按拉取请求逐一同意,不用于撰写 issue。Phil 的原话:粘贴你的提示词,而不是结果。
目前还没有任何东西可以安装。前四个讨论是别名、多格式支持、清理他们所谓的 Stoplightisms,以及规则测试。别等它,但让你的规则与它保持兼容。
这个季度我会做什么
如果我明天以 CTO 的身份加入一家公司,而 API 一团糟,这就是我的处理顺序:
-
这周就在 CI 里加一个 linter,哪怕只用默认规则集,也要让它阻断。不要
continue-on-error。除非有理由不用,否则就用 Vacuum。 -
用 Spectral 兼容的格式编写你自己的规则,放在单独的仓库里,指定负责人,配上测试和变更日志。到十二月达到第三层,仍然比大多数公司的治理水平更高。
-
在编辑器里、在 pull request 上,以及在助手输出被人类查看之前,都运行规则集。失败得越早,修复成本越低。
-
关注 OpenLint。如果联邦和覆盖率功能上线,可移植的规则集就能在同一周用上。
指南告诉人们什么是好的。Linter 在没人盯着的时候检查它,而明年你的更多契约将由某种不读 wiki 页面的东西来编写。
回复告诉我,你的规则集停在这五层中的哪一层。
取消订阅 | 1 Bd des clubs - CFC, 20200 Casablanca, Morocco
来源:Hacker News · usecommune.com