【问题标题】:Validate fixed array with Joi使用 Joi 验证固定数组
【发布时间】:2021-06-01 02:47:08
【问题描述】:

因为它是一种不同类型的“数组验证”,所以我正在努力弄清楚如何做到这一点。

本质上,我想从函数参数中获取动态的剩余参数集,并根据 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"

【问题讨论】:

  • 这只是完全绕过了数组,但是您是否考虑过在对象中传递所有函数参数?在解构时代,public async update({ id: string, model: Model }) 这样的签名并非闻所未闻。这将提供一个已经匹配您想要编写架构的方式的结构。
  • 其实我确实考虑过。但是由于 Typescript 的类型安全,如果我想避免使用 any 打字,就必须为我的所有 API 方法定义单独的接口似乎很麻烦。

标签: typescript joi


【解决方案1】:

我无法解决在特定数组上定义 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 的类型安全才能在运行时访问这些字段。所以这不是超级理想。但只要验证对象中键的顺序与我正在验证的函数中的参数顺序相匹配,它就可以工作。

【讨论】:

    猜你喜欢
    • 2021-02-05
    • 2017-07-28
    • 2018-01-14
    • 2016-10-11
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多