
Scalar Next.js Route Handlers用 Zod 4 生成 OpenAPI 描述并挂载 API Reference 的完整实践【免费下载链接】scalarScalar is an open-source API platform: Modern REST API Client Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar本文基于 Scalar 仓库中 route-handlers.md 这份官方 Recipe 展开讲解如何在纯 Next.js App Router 项目里用 Route Handlers Zod 4 显式描述路径、方法与状态码用z.toJSONSchema自动生成响应 Schema再通过scalar/nextjs-api-reference把渲染后的 API Reference 挂到/scalar路由上。读完你可以独立完成Zod Schema → OpenAPI 3.1 文档 → Scalar 可视化参考这条链路并理解ApiReference适配器在源码层面的工作方式与验证要点。方案定位显式描述路线不依赖路由自动发现Scalar 的 Next.js 配方共三种对应不同的路由层配方路由层OpenAPI 来源本文Route Handlers Zod原生 Next.js Route Handler手写pathsZod 生成 SchemaHono 配方Hono hono/zod-openapiapi.getOpenAPI31Document()从注册路由生成oRPC 配方oRPC Fetch AdapterOpenAPIGenerator从 router 元数据生成Route Handlers 配方的特点是没有自动路由发现。/openapi.json端点里写什么路径、方法、状态码Scalar 就展示什么Zod 只负责从 Schema 生成 JSON Schema这一半工作。如果你已经用 Hono 或 oRPC 这类自带路由元数据的框架也可以直接走它们的生成通道但本文覆盖的是零额外路由依赖的裸 Route Handlers 场景。另外注意边界Scalar 仓库里还有一个实验性包scalar/nextjs-openapi它是一个独立的 Route 扫描器从源码看packages/nextjs-openapi/src/openapi.ts 通过 TypeScript Compiler API 扫描app/api目录并读取 JSDoc 注释来产出 OpenAPI 3.1 文档官方标注为 pre-alpha与本文的渲染器scalar/nextjs-api-reference是两个不同的包不要混用。第一步安装依赖在 App Router 应用中安装渲染器与 Zod 4Recipe 中明确锁定了zod4因为z.toJSONSchema是 Zod 4 的转换 APInpm install scalar/nextjs-api-reference zod4第二步定义一次可复用的 Zod 响应 SchemaRecipe 的关键实践是Schema 只定义一次既作为接口数据的运行时校验parse又作为 OpenAPI 文档的 Schema 来源。以 route-handlers.md 中的示例为准// app/lib/planets.ts import { z } from zod export const planetsSchema z.array(z.object({ id: z.string(), name: z.string(), moons: z.number().int().nonnegative(), })) export const planets planetsSchema.parse([ { id: earth, name: Earth, moons: 1 }, { id: mars, name: Mars, moons: 2 }, ])要点planetsSchema描述行星目录数组这一响应结构字段约束string/int/ 非负数会原样体现在生成的 JSON Schema 中planets是同一 Schema 解析出的实际数据接口直接返回它保证文档与返回值永远一致——这是比文档和代码分开维护更省心的写法后续/openapi.json端点会直接导入planetsSchema实现单一事实来源。第三步编写数据端点Route Handler数据端点就是最普通的 Next.js Route Handler不需要引入任何 Scalar 代码// app/api/planets/route.ts import { planets } from ../../lib/planets export const GET (): Response Response.json(planets)注意导入路径app/api/planets/route.ts位于app/api/planets/目录下回app两层再进入lib所以是../../lib/planets。第四步在描述端点中生成 OpenAPI 3.1 文档新建app/openapi.json/route.ts手动声明路径、方法与状态码并用z.toJSONSchema(planetsSchema)注入响应 Schema// app/openapi.json/route.ts import { z } from zod import { planetsSchema } from ../lib/planets export const GET (): Response Response.json({ openapi: 3.1.0, info: { title: Planets API, version: 1.0.0 }, servers: [{ url: / }], paths: { /api/planets: { get: { operationId: listPlanets, summary: List planets, responses: { 200: { description: The planet catalog., content: { application/json: { schema: z.toJSONSchema(planetsSchema) } }, }, }, }, }, }, })逐段说明openapi: 3.1.0Zod 4 的z.toJSONSchema产出的是 JSON Schema 风格type: [array, null]这类 3.1 语义与 OpenAPI 3.1 的 Schema 规则兼容因此 Recipe 固定使用该版本servers: [{ url: / }]相对服务器 URL。这是本方案的一个实用特性——相对 URL 会跟随当前站点域名从本地localhost:3000到预览部署环境都能自动对应无需按环境硬编码绝对地址paths[/api/planets]路径必须与第三步 Route Handler 实际暴露的路径一致app/api/planets/route.ts对应/api/planets。这里没有任何自动发现路径写错文档就能正常渲染但请求会 404operationId/summary决定 Scalar 侧边栏中的条目命名示例中显示为List planetsresponses[200].content[application/json].schema这是 Zod 发挥作用的位置z.toJSONSchema(planetsSchema)把数组结构展开为{ type: array, items: { ...id/name/moons... } }的 JSON Schema。对于转换规则覆盖不到的边缘 Schema 类型与可选项建议以 Zod 官方文档的 JSON Schema 章节为准原 Recipe 中的外链即指向该文档。每新增一个端点就在这个对象里多写一个paths条目——这是显式描述路线的核心成本换来的是对文档结构的完全控制。第五步挂载 Scalar 到 /scalar// app/scalar/route.ts import { ApiReference } from scalar/nextjs-api-reference export const GET ApiReference({ url: /openapi.json })ApiReference返回的不是直接可挂的组件而是一个符合 Route Handler 约定的函数。仓库中 integrations/nextjs/src/ApiReference.ts 的源码可以看清它的完整行为合并默认配置内置_integration: nextjs标识与传入配置调用scalar/client-side-rendering的renderApiReference把配置渲染为一段完整 HTML 文档并注入 custom-theme.ts 中定义的双主题light/dark 的--scalar-*CSS 变量返回Content-Type: text/html的 200Response。对应的单测 integrations/nextjs/test/ApiReference.test.ts 验证了这三点ApiReference({})返回函数、响应头为text/html、渲染时默认配置被正确合入_integration: nextjs。也就是说/scalar是一个完全自包含的 HTML 端点文档数据由浏览器在页面内通过url: /openapi.json拉取——这就是为什么openapi.json与scalar必须是两个独立路由。url以外的其他配置项主题、认证、布局等类型定义为HtmlRenderingConfiguration可参考仓库的 configuration.md 完整传入。验证与预期结果启动并验证与 Recipe 给出的验收标准一致npm run dev打开http://localhost:3000/scalar侧边栏应出现List planets条目打开Test Request面板发送请求预期返回200响应体为 Earth 与 Mars 两条记录直接访问/openapi.json应能看到/api/planets路径及由 Zod 生成的数组响应 Schema。小结与选型建议本配方的分工很清晰Zod 管Schema 从哪来你手写paths管文档长什么样scalar/nextjs-api-reference管怎么渲染。三者解耦任何一环都可替换相对serversURL 让同一份文档在本地与预览部署间零配置迁移若你的路由层本身就是 Hono 或 oRPC改用对应配方hono.md、orpc.md可以把paths也自动化若想尝试自动扫描 Route Handlers 的方案可关注仓库中的实验包 packages/nextjs-openapipre-alpha默认扫描目录为app/api见 packages/nextjs-openapi/src/openapi.ts 的OpenAPIConfig定义它独立于本文的渲染器包。【免费下载链接】scalarScalar is an open-source API platform: Modern REST API Client Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考