OpenAPI 文档工具怎么选:Swagger UI、Redoc、Scalar 到 Starlight,我最后留了哪个

🔑 关键词:OpenAPI 3.1, Swagger UI, Redocly, Scalar, API 文档

📖 摘要:一篇不太客观的 API 文档工具选型笔记:Swagger UI、Redoc、Scalar、Starlight 各自真实的坑,OpenAPI 3.0 升 3.1 的几个具体差异,以及让文档不腐烂的三道 CI 闸门。

一、先说背景

图片

前两年待过一个小团队,后端六个人,内部服务十四个,对外 API 三个。文档在 Confluence 上,命名大概是「订单API说明-v3-最终版-别删」这种。每个季度都有人问「这个字段到底是不是必填」,然后大家去翻代码。

后来我们把三个 API 全迁到了 OpenAPI,用 Swagger UI 渲染。迁移那天挺爽的,两周后没人再打开过那份 yaml。原因很简单:写代码和改 spec 是两件事,而人只有两只手。

真正让 spec 活过来的,不是我换了哪个渲染器,是我在 CI 里塞了三行命令。这个是后面第五节的重点,前面都是铺垫。

二、选型时大家盯的地方,基本都不重要

我见过太多对比文章在比主题色、暗黑模式、侧边栏折叠动画。这些在 demo 里确实好看,但你团队里真正的用户是「刚接手的实习生」和「半夜十二点排查线上问题的你自己」,他们不关心动画。

我只用三个问题筛工具:

图片

  1. 这个 spec 能不能被 lint?规则能不能自己定义,而不是只能开它内置那几条。
  2. 文档里的 example 能不能直接拿去起 mock server?不能的话,example 就是写给领导看的装饰品。
  3. 每次改 OpenAPI 文件,CI 能不能告诉我「你删了一个响应字段,下游有三个调用方在依赖它」?

三个都是否,那这工具再漂亮,也只是个静态页面生成器。

三、几个工具的实际差别(不是从官网抄的那种)

先拆一个被搞混的事:Swagger UI、Redoc、Scalar 是 API reference 渲染器;Mintlify、Docusaurus、Starlight 是站点框架。前者解决「怎么把一个 yaml 渲染成人能看的页面」,后者解决「整个文档站怎么搭、路由怎么分、版本怎么管」。拿 Mintlify 和 Swagger UI 比,约等于拿 Next.js 和 React 比。

工具 定位 我遇到的好 我遇到的坑
Swagger UI 渲染器 谁都会用,插件多,swagger-ui-dist 直接丢 CDN 就行 端点上百之后首屏明显卡;搜索基本等于没有;对 OpenAPI 3.1 的支持长期滞后,webhooks 那块渲染不出来
Redoc 渲染器 三栏布局,左侧导航右侧多语言样例,redocly build-docs openapi.yaml -o docs.html 一条命令出单文件,扔 nginx 就完事 社区版的 Try it 能力弱,改样式要跟它的主题变量较劲
Scalar 渲染器 默认样式确实顺眼,代码样例能一键切 curl / fetch / Python,不用自己写模板 生态薄,schema 写得野一点(oneOf 套 allOf 再套 $ref)会直接渲染成空白
Starlight 站点框架 Astro 生态,MDX 随便写,SEO 和构建速度都不错 API reference 得自己接,它不管这事
Mintlify 站点 + 托管 开箱即用,写 MDX 就行,搜索和 AI 问答是现成的 托管方案,要花钱,私有化部署得单独谈
Docusaurus 站点框架 插件生态成熟,docusaurus-plugin-openapi-docs 能直接生成 API 页 构建慢,我这边一个三百来页的站要跑四分多钟

数字我不给太死。这类工具版本迭代快,我上次认真量 bundle 是去年底的事,Scalar 的入口体积比 Swagger UI 小一大截,具体差几倍你现在自己 npx 一把就知道。别信任何文章里的数字,包括我这篇。

四、OpenAPI 3.0 升 3.1 这件事,值得单独说

图片

很多团队卡在 3.0 不敢升,主要怕工具不认。列几个我实际踩过的差异:

  • nullable: true 在 3.1 里没了,要写成 type: ["string", "null"]。升级脚本好写,但如果你有几十个 schema 手工改会崩溃。
  • example(单数)和 examples(复数)在 3.0 里是 OpenAPI 自己的关键字;3.1 全面对齐 JSON Schema 2020-12 之后,examples 变成了数组,语义变了。我见过一个团队升级后 Swagger UI 里样例全部消失,就是因为这个。
  • exclusiveMinimum 在 3.0 里是布尔值配合 minimum 用,3.1 里直接是个数字。这坑很隐蔽,lint 不报,只有 mock 出来的边界值不对才会被发现。
  • 3.1 新增了顶层 webhooks 字段,可以描述回调。但支持它的渲染器到 2024 年还是少数。

我的建议:新项目直接上 3.1,老项目先别动,除非你有明确的、非升不可的理由(比如要用 webhooks 描述回调)。升级动作本身十分钟,改工具链和排查渲染问题可能两周。

五、真正让文档活下来的三道闸

回到开头那句。渲染器决定「好不好看」,CI 决定「活不活」。我在 .github/workflows 里加了三个东西。

第一道,Spectral。

图片

npx @stoplight/spectral-cli lint openapi.yaml --ruleset .spectral.yaml

内置规则先跑 spectral:oas,然后我自己加了几条。.spectral.yaml 长这样:

extends: ["spectral:oas"]
rules:
  operation-operationId: error
  oas3-valid-schema-example: error

另外还加了一条自定义规则:每个 4xx 响应必须带 examples。以及每个 description 不许超过 120 个字符——是的,文档写太长没人看,这条规则被同事吐槽过,但半年后没人提了。

第二道,用 example 起 mock,让测试打上去。

npx @stoplight/prism-cli mock openapi.yaml -p 4010

图片

合约测试跑一遍。这一步能抓出「schema 写的是 string,example 里给的是整数」这种低级错误,而这恰恰是接口文档里出现频率最高的错误。

第三道,breaking change 检测。

oasdiff breaking base.yaml head.yaml --fail-on ERR

删字段、改类型、把可选改必填,都会报出来。这条拦下来的事故,比我们任何一次 code review 都多。

六、文档里最值钱的部分,通常没人认真写

一个 API 文档,八成篇幅在列端点、参数、返回值。但真正降低支持成本的,是下面这三块,而且它们经常是空的:

  • 错误码表。 不是「400 请求错误」这种废话。是「40001 参数缺失」「40002 手机号格式非法」这类业务码,加上「遇到之后调用方应该怎么办」。
  • 可直接复制的 curl。 要带脱敏后的真实 token 占位符、真实的时间戳格式、真实的分页参数。粘上去就能跑通那种。
  • 限流、分页、幂等、重试。 这四个单独开一节写,别散在参数说明里。分页要说清楚:limit 最大多少、超了会怎样、游标稳不稳定。

图片

我的粗略统计是,接入方提的问题里有一大半能靠这三块解决。剩下那部分,才是文档解决不了、必须打电话的那种。

七、我最后留了什么

内部:Redoc 单文件 + Spectral + oasdiff,扔在一个 nginx 里,改完 spec 跑 CI 自动部署。

对外:Starlight 搭站点,API reference 用 Scalar 的组件嵌进 MDX,普通指南手写 Markdown。

为什么不统一成一个?因为这两类文档的读者根本不是一批人。内部那批人只想知道参数和错误码,越快越好,别跟他讲品牌调性;外部那批人要看 quickstart、要 SDK、要在手机上看。

工具是按读者分的,不是按团队分的。这一点想明白,选型就没那么纠结了。

🏷️ 标签: