Skip to content

OpenAPI 文档 ​

ts
import { documented, openApiRoutes } from '@hestjs/openapi';

const app = createApp(AppModule, {
  routes: (hono, resolve) =>
    hono.get(
      '/users/:id',
      documented({ summary: '查单个用户', tags: ['users'] }),
      (c) => resolve(Users).detail(c),
    ),
});

app.hono.route('/', openApiRoutes({
  hono: app.hono,
  info: { title: 'HestJS API', version: '1.0.0' },
}));

挂上之后:

路径内容
/openapi.jsonOpenAPI 3.1 文档
/docsScalar API 参考界面

documented 也是一段中间件 ​

它什么都不做,只把说明挂在自己身上。因为 hono.routes 会连中间件一起记下来, buildOpenApiDocument 就能按 (method, path) 把同一路由上的元数据聚合起来。

和 validate() 一样,做成中间件是为了不碰 handler、不影响 RPC 类型。

它知道什么,不知道什么 ​

自动读到的:

  • 路由表(直接来自 hono.routes,不用传模块图)
  • 路径参数(:id → {id},required: true)
  • validate({ jsonSchema }) 登记的请求体与查询参数

读不到、也不会编造的:

  • 中间件注册出来的通配条目(ALL /* 之类)会被跳过
  • 响应结构(除非写 documented({ responses }))
  • 没有任何 schema 的请求体(文档里就没有 requestBody)

猜不出来就不写。 一份撒谎的文档比没有文档更糟。

完整例子 ​

ts
hono
  .get(
    '/users',
    documented({
      summary: '列出全部用户',
      tags: ['users'],
      responses: { '200': { description: '用户列表', jsonSchema: { type: 'array' } } },
    }),
    (c) => users.list(c),
  )
  .post(
    '/users',
    validate({ body: CreateUser, jsonSchema: { body: z.toJSONSchema(CreateUser) } }),
    documented({
      summary: '创建用户',
      tags: ['users'],
      responses: { '201': { description: '创建成功' } },
    }),
    (c) => users.create(c),
  );

配置项 ​

选项默认说明
hono——通常是 app.hono,必填
info——OpenAPI 必填字段
servers无服务地址列表
jsonPath/openapi.json文档 JSON 路径
docsPath/docsUI 路径
uitrue关掉就只出 JSON

只要文档对象 ​

ts
import { buildOpenApiDocument } from '@hestjs/openapi';

const document = buildOpenApiDocument(app.hono, {
  info: { title: 'HestJS API', version: '1.0.0' },
});

await Bun.write('./openapi.json', JSON.stringify(document, null, 2));

适合在 CI 里导出契约、或者喂给别的工具。

与 validation 的关系 ​

没有关系。 openapi 只依赖 core,读的是 core 里定义的 ValidationRouteMeta 形状,不是 validation 包的导出。

这样没写校验的路由也能出文档,两个插件可以各装各的。