名词解释
- 类型推断 TypeScript 的能力,无需显式标注类型注解,编译器自动根据上下文推导变量类型。Hono 大量利用类型推断,使得路径参数、验证后的请求体等都能自动获得正确类型,减少手动标注工作量。
-
泛型约束
通过 TypeScript 泛型(
<T extends SomeType>)限制类型参数的范围。Hono 的Hono<{ Bindings: Env; Variables: Vars }>就是典型的泛型约束,用于传递环境变量类型和 Context 变量类型。 -
infer 关键字
TypeScript 条件类型中的关键字,用于从类型中提取子类型。例如
type Input = z.infer<typeof schema>会自动从 Zod schema 中提取出对应的 TypeScript 类型,无需手动定义接口。 -
RPC 模式
Remote Procedure Call,远程过程调用。Hono 的 RPC 模式允许将服务端路由类型导出,客户端通过
hc<AppType>(url)创建类型安全的 HTTP 客户端,调用 API 就像调用本地函数,并获得完整的类型提示和错误检查。
Zod Validator
Zod 是 TypeScript 优先的 Schema 验证库。@hono/zod-validator 将 Zod 与 Hono 无缝集成:
# 安装依赖
bun add zod @hono/zod-validator
JSON Body 验证
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const app = new Hono()
// 定义 Schema
const createUserSchema = z.object({
name: z.string().min(2, '名字至少2个字符').max(50),
email: z.string().email('邮箱格式不正确'),
age: z.number().int().min(0).max(150).optional(),
role: z.enum(['user', 'admin']).default('user'),
})
// 类型自动推断(无需手动定义接口)
type CreateUser = z.infer<typeof createUserSchema>
// 等同于:{ name: string; email: string; age?: number; role: "user" | "admin" }
app.post(
'/users',
zValidator('json', createUserSchema), // 验证 JSON body
(c) => {
const data = c.req.valid('json') // 完全类型安全!
// data.name → string,data.role → "user" | "admin"
return c.json({ created: data }, 201)
}
)
路径参数验证
const userIdSchema = z.object({
id: z.string().uuid('ID 必须是有效的 UUID'),
})
app.get(
'/users/:id',
zValidator('param', userIdSchema),
(c) => {
const { id } = c.req.valid('param') // id: string(UUID 格式保证)
return c.json({ id })
}
)
查询参数验证
const listQuerySchema = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
search: z.string().optional(),
sort: z.enum(['asc', 'desc']).default('desc'),
})
app.get(
'/users',
zValidator('query', listQuerySchema),
(c) => {
const { page, limit, search, sort } = c.req.valid('query')
// page → number(z.coerce 自动将字符串转换为数字)
return c.json({ page, limit, search, sort })
}
)
自定义验证错误响应
zValidator('json', createUserSchema, (result, c) => {
if (!result.success) {
// 自定义错误响应格式
return c.json({
error: 'Validation failed',
details: result.error.issues.map((issue) => ({
field: issue.path.join('.'),
message: issue.message,
})),
}, 422)
}
})
RPC 模式:端到端类型安全
Hono RPC 是最强大的特性之一——服务端路由定义即是客户端的类型契约:
服务端定义(带类型的路由)
// server/routes/users.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const users = new Hono()
.get('/', (c) => c.json({ users: [{ id: '1', name: 'Alice' }] }))
.post(
'/',
zValidator('json', z.object({
name: z.string(),
email: z.string().email(),
})),
async (c) => {
const body = c.req.valid('json')
return c.json({ id: 'new-id', ...body }, 201)
}
)
.get('/:id', (c) => c.json({ id: c.req.param('id') }))
export default users
export type UsersRoute = typeof users
// server/index.ts
import { Hono } from 'hono'
import users from './routes/users'
const app = new Hono().route('/users', users)
export default app
export type AppType = typeof app // 导出整个 app 类型
客户端使用(完整类型推断)
// client/api.ts
import { hc } from 'hono/client'
import { type AppType } from '../server'
// 创建类型安全的 HTTP 客户端
const client = hc<AppType>('http://localhost:3000')
// 使用——完全类型安全,有 IDE 自动补全!
const getUsers = async () => {
const res = await client.users.$get()
const data = await res.json()
// data.users → { id: string; name: string }[] ← 自动推断!
return data.users
}
const createUser = async () => {
const res = await client.users.$post({
json: {
name: 'Bob',
email: 'bob@example.com',
// age: 'wrong' ← TypeScript 报错!类型检查在编译时生效
},
})
return await res.json()
}
const getUser = async (id: string) => {
const res = await client.users[':id'].$get({ param: { id } })
return await res.json()
}
RPC 的核心价值:服务端修改路由(改变路径、请求体类型、响应类型)时,客户端代码会立即出现 TypeScript 编译错误,无需等到运行时才发现问题。这彻底消灭了前后端接口不一致的问题,是现代全栈开发的最佳实践。
OpenAPI 文档生成
# 安装
bun add @hono/zod-openapi
import { OpenAPIHono, createRoute } from '@hono/zod-openapi'
import { z } from 'zod'
const app = new OpenAPIHono()
// 使用 createRoute 定义带 OpenAPI 元数据的路由
const getUserRoute = createRoute({
method: 'get',
path: '/users/{id}',
summary: 'Get a user by ID',
tags: ['Users'],
request: {
params: z.object({ id: z.string().openapi({ example: '123' }) }),
},
responses: {
200: {
description: 'User found',
content: {
'application/json': {
schema: z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
}),
},
},
},
404: { description: 'User not found' },
},
})
app.openapi(getUserRoute, (c) => {
const { id } = c.req.valid('param')
return c.json({ id, name: 'Alice', email: 'alice@example.com' })
})
// 自动生成 OpenAPI JSON
app.doc('/openapi.json', {
openapi: '3.0.0',
info: { title: 'My API', version: '1.0.0' },
})
// Swagger UI(需要额外安装 @hono/swagger-ui)
import { swaggerUI } from '@hono/swagger-ui'
app.get('/docs', swaggerUI({ url: '/openapi.json' }))
Zod Validator vs OpenAPI Hono:zValidator 适合快速开发,只需要验证功能;OpenAPIHono + createRoute 适合需要同时提供 Swagger 文档的项目,代码量更多但 API 文档自动生成。两者的验证逻辑都是 Zod,可以根据项目需求选择。