问题描述
正在努力弄清楚如何做到这一点,因为它是一种不同类型的“数组验证”。
本质上,我想从函数参数中获取静态参数的动态集,并根据 REST api 的模式验证它们。例如:
@Validation(Schema.update)
public async update(id: string,model: Model) => { }
export function Validation(schema: ObjectSchema) {
return (target: any,propName: string | symbol,descriptor: PropertyDescriptor): void => {
const originalMethod = descriptor.value!;
descriptor.value = function (...rest: any[]): ApiResult {
const { error } = schema.validate({ ...rest });
if (error) {
console.error(error.message);
return new ErrorApiResult({ statusCode: 400,message: error?.message });
}
return originalMethod.apply(this,arguments);
};
};
}
目前,我想指出这非常有效,除非我必须像这样创建验证模式:
export const Schema = {
update: Joi.object({
0: Joi.string(),1: ModelSchema,}),}
这样做的主要问题是验证错误消息 Joi 生成的字段标记为 0.user.name
而不是 model.user.name
等。
我想改为编写上述端点架构,如:
export const Schema = {
update: Joi.object({
id: Joi.string().required(),model: ModelSchema,}
但我不知道该怎么做。看看Joi.array(),它似乎只设计用于处理对象的集合,而不是严格的参数数组。
编辑:
我尝试使用 .label()
方法来更改错误消息中的标签,但如果错误在于嵌套键,则这不起作用。例如,如果我的 id
参数没有正确验证它会工作,但如果我的 ModelSchema
未能在子属性上验证它不会正确显示。它仍然在错误消息中显示为 "1.user.name"
。
解决方法
我无法解决在特定数组上定义 Joi 验证的问题,但我能够使用我的 Joi 架构元数据来构建满足 Joi 架构的自定义对象,如下所示:
export function Validation(schema: ObjectSchema) {
return (target: any,propName: string | symbol,descriptor: PropertyDescriptor): void => {
const originalMethod = descriptor.value!;
descriptor.value = function (...rest: any[]): ApiResult {
const validationObject: any = {};
const keys: string[] = Array.from((schema as any)._ids._byKey.keys());
for (let i = 0; i < keys.length; i++) {
validationObject[keys[i]] = rest[i];
}
const { error } = schema.validate(validationObject);
if (error) {
console.error(error.message);
return new ErrorApiResult({ statusCode: 400,message: error?.message });
}
return originalMethod.apply(this,arguments);
};
};
}
我必须打破 Typescript 的类型安全才能在运行时访问这些字段。所以这不是非常理想。但是只要验证对象中键的顺序与我正在验证的函数中参数的顺序相匹配,它就可以工作。