示例说明
Fastify 的 schema 机制把校验与序列化前移到路由注册时:请求进来先过校验,处理器拿到的 body 已是窄化类型;响应走快速序列化器,多余字段自动剥离。接入 Zod 类型提供者后,schema 从 JSON Schema 换成 Zod 定义,类型推断直接跟随——校验规则、运行时检查与 TypeScript 类型三者出自同一份声明。
技术要点
- withTypeProvider 挂载 Zod 推断能力
- body 与各状态码响应共用一套 schema
- 响应多余字段在序列化时被剥离
代码解读
CreateOrderSchema 用嵌套对象分别约束 body 与 201、400 两种响应形态;处理器里 request.body 的类型由 body schema 推断,SKU 与数量直接解构使用。售罄分支返回 400 结构,成功分支按 201 schema 构造回执,非法数量在进入处理器前已被拦截。
使用建议
schema 复杂度高时拆分为可组合的 Zod 片段。响应 schema 要覆盖全部可能状态码否则序列化会放行未声明形态。此模式与 OpenAPI 生成插件配合可直接产出文档。
代码示例
import Fastify from 'fastify';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
const app = Fastify({
logger: true,
}).withTypeProvider<ZodTypeProvider>();
const CreateOrderSchema = z.object({
body: z.object({
sku: z.string().min(3),
quantity: z.number().int().min(1).max(99),
}),
response: {
201: z.object({ id: z.string().uuid(), total: z.number() }),
400: z.object({ error: z.string() }),
},
});
app.post('/orders', { schema: CreateOrderSchema }, async (request, reply) => {
const { sku, quantity } = request.body;
if (sku === 'SOLD-OUT') {
return reply.code(400).send({ error: 'sku unavailable' });
}
return reply.code(201).send({
id: crypto.randomUUID(),
total: quantity * 19.9,
});
});
await app.listen({ port: 3000 });