使用 Joi 验证固定数组
Validate fixed array with Joi
正在努力弄清楚我该如何做到这一点,因为它是一种不同类型的“数组验证”。
本质上,我想从函数参数中获取动态的剩余参数集,并根据 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 的类型安全才能在运行时访问这些字段。所以这不是超级理想。但只要验证对象中键的顺序与我正在验证的函数中参数的顺序相匹配,它就可以工作。
正在努力弄清楚我该如何做到这一点,因为它是一种不同类型的“数组验证”。
本质上,我想从函数参数中获取动态的剩余参数集,并根据 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 的类型安全才能在运行时访问这些字段。所以这不是超级理想。但只要验证对象中键的顺序与我正在验证的函数中参数的顺序相匹配,它就可以工作。