Fastify+Yup验证报错:schema.validateSync不是函数,需兼顾Swagger生成
解决Fastify中Yup验证与Swagger文档共存的问题
问题根源
你遇到的schema.validateSync is not a function错误,是因为validatorCompiler里拿到的schema是JSON Schema对象,不是Yup实例——JSON Schema本身没有validateSync方法。而直接用Yup对象替换schema里的params时,Fastify的Swagger插件只识别JSON Schema格式,所以无法生成文档。
解决方案
要同时满足Yup验证和Swagger文档生成,核心是让路由配置同时提供Swagger所需的JSON Schema,以及Yup验证所需的实例。下面提供两种可行方案:
方案一:手动维护双Schema
在路由配置中,JSON Schema用于生成Swagger文档,单独定义的Yup Schema用于验证逻辑,在validatorCompiler中根据请求部分(params/query/body等)匹配对应的Yup实例:
const yup = require("yup"); const yupOptions = { strict: false, abortEarly: false, stripUnknown: true, recursive: true, }; async function isUsernameAvailable(fastify: any, _options: Object) { const users = fastify.mongo.db.collection("users"); // 1. 定义Yup验证Schema const paramsYupSchema = yup.object({ username: yup.string().lowercase().max(12).min(1).required() }); fastify.get( "/api/v1/onboarding/isUsernameAvailable/:username", { schema: { // 2. 定义JSON Schema用于Swagger生成 params: { type: "object", properties: { username: { type: "string", maxLength: 12, minLength: 1, description: "用户名" }, }, required: ["username"], }, response: { 200: { type: "object", properties: { available: { type: "boolean", description: "用户名是否可用", }, }, }, }, }, validatorCompiler: ({ httpPart }: any) => { // 3. 根据请求部分选择对应的Yup Schema let yupSchema; switch (httpPart) { case "params": yupSchema = paramsYupSchema; break; // 如果有query/body,在这里添加对应分支 default: return (data: any) => ({ value: data }); } return function (data: any) { try { const result = yupSchema.validateSync(data, yupOptions); return { value: result }; } catch (e) { return { error: e }; } }; }, }, async (request: any, _reply: any) => { // 这里的request.params已经是Yup处理后的(比如转成小写) const { username } = request.params; const foundNUsernames = await users.countDocuments( { username }, { limit: 1 } ); const available: boolean = foundNUsernames === 0; return { available }; } ); } export { isUsernameAvailable };
方案二:自动转换Yup到JSON Schema
使用yup-to-json-schema工具,将Yup Schema自动转换成JSON Schema,避免手动维护双份规则:
- 安装依赖:
npm install yup-to-json-schema
- 修改代码:
const yup = require("yup"); const yupToJsonSchema = require("yup-to-json-schema"); const yupOptions = { strict: false, abortEarly: false, stripUnknown: true, recursive: true, }; async function isUsernameAvailable(fastify: any, _options: Object) { const users = fastify.mongo.db.collection("users"); // 1. 只定义Yup Schema const paramsYupSchema = yup.object({ username: yup.string().lowercase().max(12).min(1).required() }); // 2. 自动转换为JSON Schema const paramsJsonSchema = yupToJsonSchema(paramsYupSchema); fastify.get( "/api/v1/onboarding/isUsernameAvailable/:username", { schema: { // 3. 用转换后的JSON Schema生成Swagger params: paramsJsonSchema, response: { 200: { type: "object", properties: { available: { type: "boolean", description: "用户名是否可用", }, }, }, }, }, validatorCompiler: ({ httpPart }: any) => { // 4. 直接用Yup Schema验证 let yupSchema; switch (httpPart) { case "params": yupSchema = paramsYupSchema; break; default: return (data: any) => ({ value: data }); } return function (data: any) { try { const result = yupSchema.validateSync(data, yupOptions); return { value: result }; } catch (e) { return { error: e }; } }; }, }, async (request: any, _reply: any) => { const { username } = request.params; const foundNUsernames = await users.countDocuments( { username }, { limit: 1 } ); const available: boolean = foundNUsernames === 0; return { available }; } ); } export { isUsernameAvailable };
注意事项
- 方案二的自动转换可能无法覆盖Yup的所有高级规则(比如自定义验证器),如果有特殊逻辑,建议用方案一手动补充JSON Schema的描述。
- 无论哪种方案,
validatorCompiler里都要确保拿到的是Yup实例,而不是JSON Schema对象,这样才能调用validateSync。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

