23.07-OpenAPI文档生成
要点
- Hono 可以从 Zod schema 自动生成 OpenAPI 3.0 文档
- 使用
@hono/zod-openapi扩展可以同时做参数校验和文档生成 - 提供 Swagger UI 交互式文档界面
- 前端可以从 OpenAPI spec 自动生成类型安全的客户端
内容
1. 安装依赖
npm install @hono/zod-openapi @hono/swagger-ui2. 创建 OpenAPI 应用
// src/index.ts
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
import { SwaggerUI } from '@hono/swagger-ui'
const app = new OpenAPIHono()
// 定义路由
const route = createRoute({
method: 'post',
path: '/v1/chat/completions',
request: {
body: {
content: {
'application/json': {
schema: z.object({
messages: z.array(z.object({
role: z.enum(['system', 'user', 'assistant']).openapi({
description: '消息角色',
example: 'user',
}),
content: z.string().openapi({
description: '消息内容',
example: '你好',
}),
})),
model: z.enum(['gpt-4', 'gpt-3.5-turbo']).openapi({
description: '模型名称',
example: 'gpt-4',
}),
}),
},
},
},
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({
id: z.string().openapi({ description: '请求 ID' }),
choices: z.array(z.object({
message: z.object({
role: z.enum(['assistant']),
content: z.string(),
}),
finish_reason: z.enum(['stop', 'length']),
})),
usage: z.object({
prompt_tokens: z.number(),
completion_tokens: z.number(),
total_tokens: z.number(),
}),
}),
},
},
description: '成功响应',
},
},
})
// 实现路由
app.openapi(route, async (c) => {
const body = c.req.valid('json')
// 调用 LLM
const result = await callLLM(body)
return c.json(result, 200)
})
// 生成 OpenAPI spec
app.doc('/doc', {
openapi: '3.0.0',
info: {
title: 'AI Gateway API',
version: '1.0.0',
description: 'AI 网关 API 文档',
},
servers: [
{
url: 'http://localhost:8787',
description: '开发环境',
},
{
url: 'https://api.example.com',
description: '生产环境',
},
],
})
// 提供 Swagger UI
app.get('/swagger', SwaggerUI({ url: '/doc' }))
export default app3. OpenAPI 注解
3.1 字段描述
z.object({
name: z.string().openapi({
description: '用户名称',
example: 'Alice',
minLength: 1,
maxLength: 100,
}),
email: z.string().email().openapi({
description: '邮箱地址',
example: '[email protected]',
}),
age: z.number().openapi({
description: '年龄',
example: 25,
minimum: 0,
maximum: 150,
}),
})3.2 枚举类型
z.enum(['active', 'inactive', 'pending']).openapi({
description: '用户状态',
example: 'active',
})3.3 嵌套对象
z.object({
user: z.object({
id: z.string(),
name: z.string(),
}).openapi({
description: '用户信息',
}),
posts: z.array(z.object({
id: z.string(),
title: z.string(),
})).openapi({
description: '文章列表',
}),
})4. 复用 Schema
// src/schemas/user.ts
import { z } from '@hono/zod-openapi'
export const UserSchema = z.object({
id: z.string().openapi({ description: '用户 ID' }),
name: z.string().openapi({ description: '用户名称' }),
email: z.string().email().openapi({ description: '邮箱' }),
})
export const CreateUserSchema = UserSchema.omit({ id: true })
export const UserListSchema = z.object({
users: z.array(UserSchema),
total: z.number(),
})// src/index.ts
import { UserSchema, CreateUserSchema, UserListSchema } from './schemas/user'
// 获取用户
app.openapi(
createRoute({
method: 'get',
path: '/api/users/:id',
request: {
params: z.object({
id: z.string(),
}),
},
responses: {
200: {
content: {
'application/json': {
schema: UserSchema,
},
},
description: '成功',
},
},
}),
async (c) => {
const { id } = c.req.valid('params')
const user = await getUser(id)
return c.json(user, 200)
}
)
// 创建用户
app.openapi(
createRoute({
method: 'post',
path: '/api/users',
request: {
body: {
content: {
'application/json': {
schema: CreateUserSchema,
},
},
},
},
responses: {
201: {
content: {
'application/json': {
schema: UserSchema,
},
},
description: '创建成功',
},
},
}),
async (c) => {
const body = c.req.valid('json')
const user = await createUser(body)
return c.json(user, 201)
}
)5. 认证配置
app.doc('/doc', {
openapi: '3.0.0',
info: {
title: 'AI Gateway API',
version: '1.0.0',
},
components: {
securitySchemes: {
BearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: 'JWT 认证 token',
},
ApiKeyAuth: {
type: 'apiKey',
in: 'header',
name: 'X-API-Key',
description: 'API Key 认证',
},
},
},
security: [
{ BearerAuth: [] },
],
})6. 分组和标签
// 用户相关
app.openapi(
createRoute({
method: 'get',
path: '/api/users',
tags: ['用户管理'],
// ...
}),
// ...
)
// 聊天相关
app.openapi(
createRoute({
method: 'post',
path: '/api/chat',
tags: ['AI 聊天'],
// ...
}),
// ...
)7. 导出 OpenAPI spec
7.1 JSON 格式
curl http://localhost:8787/doc > openapi.json7.2 YAML 格式
npm install js-yamlimport yaml from 'js-yaml'
app.get('/doc.yaml', (c) => {
const spec = app.getOpenAPIDocument({
openapi: '3.0.0',
info: { title: 'AI Gateway', version: '1.0.0' },
})
return c.text(yaml.dump(spec), 200, {
'Content-Type': 'application/x-yaml',
})
})8. 前端生成客户端
npx @openapitools/openapi-generator-cli generate \
-i http://localhost:8787/doc \
-g typescript-fetch \
-o ./generated// 使用生成的客户端
import { UsersApi, ChatApi } from './generated'
const usersApi = new UsersApi()
const user = await usersApi.getUser('123')
const chatApi = new ChatApi()
const response = await chatApi.createChat({
messages: [{ role: 'user', content: '你好' }],
})9. 实战:完整的 API 文档
// src/index.ts
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
import { SwaggerUI } from '@hono/swagger-ui'
const app = new OpenAPIHono()
// 公共 Schema
const ErrorSchema = z.object({
error: z.string().openapi({ description: '错误信息' }),
code: z.string().openapi({ description: '错误代码' }),
})
// 用户路由
const getUserRoute = createRoute({
method: 'get',
path: '/api/users/:id',
tags: ['用户'],
summary: '获取用户信息',
description: '根据 ID 获取用户详细信息',
request: {
params: z.object({
id: z.string().openapi({ description: '用户 ID', example: '123' }),
}),
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({
id: z.string(),
name: z.string(),
email: z.string(),
}),
},
},
description: '成功',
},
404: {
content: {
'application/json': {
schema: ErrorSchema,
},
},
description: '用户不存在',
},
},
})
app.openapi(getUserRoute, async (c) => {
const { id } = c.req.valid('params')
const user = await getUser(id)
if (!user) {
return c.json({ error: 'Not found', code: 'USER_NOT_FOUND' }, 404)
}
return c.json(user, 200)
})
// OpenAPI 文档
app.doc('/doc', {
openapi: '3.0.0',
info: {
title: 'AI Gateway API',
version: '1.0.0',
description: 'AI 网关 API 文档,提供用户管理、AI 聊天等功能',
contact: {
name: 'API Support',
email: '[email protected]',
},
},
servers: [
{ url: 'http://localhost:8787', description: '开发环境' },
{ url: 'https://api.example.com', description: '生产环境' },
],
tags: [
{ name: '用户', description: '用户管理相关接口' },
{ name: 'AI 聊天', description: 'AI 聊天相关接口' },
],
})
// Swagger UI
app.get('/swagger', SwaggerUI({ url: '/doc' }))
export default app10. 小结
OpenAPI 文档生成的关键点:
- 自动从 Zod 生成:使用
@hono/zod-openapi同时做校验和文档生成 - OpenAPI 注解:使用
.openapi()添加描述、示例、约束 - 复用 Schema:抽取公共 Schema,避免重复定义
- 认证配置:在 OpenAPI spec 中声明认证方式
- Swagger UI:提供交互式文档界面
- 客户端生成:前端可以从 OpenAPI spec 自动生成类型安全的客户端
一句话带走:
Hono + Zod OpenAPI = 参数校验 + 文档生成 + 类型推导,一次定义,三处复用。