【问题标题】:Validate each Map<string, number> value using class-validator使用类验证器验证每个 Map<string, number> 值
【发布时间】:2022-04-09 23:51:58
【问题描述】:

我正在尝试对由我的一个 DTO 建模的 JSON 输入执行简单验证。 对象属性之一是Map&lt;string, number&gt; 类型。示例输入:

{
  "type": "CUSTOM",
  "is_active": true,
  "current_plan_day": 1,
  "custom_warmup_plan": {
    "1": 123,
    "2": 456
}

在我的控制器上,我使用 DTO 来指定主体类型。该类以及类验证器装饰器是这样的:

    export class CreateWarmupPlanRequestDto {
      @IsEnum(WarmupPlanType)
      type: string;
    
      @IsOptional()
      @IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 0 })
      @IsPositive()
      hard_cap: number | null;
    
      @IsBoolean()
      is_active: boolean;
    
      @IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 0 })
      @IsPositive()
      current_plan_day: number;
    
      @IsOptional()
      @IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 0 })
      @IsPositive()
      previous_plan_day: number | null;
    
      @IsOptional()
      @IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 0 }, { each: true })
      @IsPositive({ each: true })
      custom_warmup_plan: Map<string, number>;  // PROBLEM HERE
    }

我希望将custom_warmup_plan 的每个值验证为现有的正整数。 对象的其他属性的验证工作正常且符合预期,但对于我的示例输入,我不断收到错误(2 条错误消息,已加入):

{
    "message": "each value in custom_warmup_plan must be a positive number. |#| each value in custom_warmup_plan must be a number conforming to the specified constraints",
    "statusCode": 400,
    "timestamp": "2021-07-29T13:18:29.331Z",
    "path": "/api/warmup-plan/bc4c3f0e-8e77-46de-a46a-a908edbdded5"
}

这方面的文档似乎很简单,但我就是无法让它工作。 我也玩过一个简单的Map&lt;string, string&gt;@IsString(each: true) 验证器,但这似乎也不起作用。

有什么想法吗?

版本:

"@nestjs/common": "^8.0.0",
"@nestjs/core": "^8.0.0",
"@nestjs/mapped-types": "^1.0.0",
"@nestjs/platform-express": "^8.0.0",
"class-transformer": "^0.4.0",
"class-validator": "^0.13.1",

【问题讨论】:

    标签: validation nestjs class-validator


    【解决方案1】:

    来自docs

    如果您的字段是一个数组,并且您想要对数组中的每个项目执行验证,您必须指定一个特殊的 each: true 装饰器选项

    如果您希望能够验证地图,您可以编写自定义装饰器并传入class-validator 函数列表来验证键和值。例如,下面的装饰器将键和值的验证函数列表作为输入(例如传入isStringisObject 等...,class-validator 有一个对应的function you can call for all the validation decorators they provide

    export function IsMap(
      key_validators: ((value: unknown) => boolean)[],
      value_validators: ((value: unknown) => boolean)[],
      validationOptions?: ValidationOptions
    ) {
      return function (object: unknown, propertyName: string) {
        registerDecorator({
          name: 'isMap',
          target: (object as any).constructor,
          propertyName: propertyName,
          options: validationOptions,
          validator: {
            validate(value: unknown, args: ValidationArguments) {
              if (!isObject(value)) return false;
              const keys = Object.keys(value);
              const is_invalid = keys.some((key) => {
                const is_key_invalid = key_validators.some((validator) => !validator(key));
                if (is_key_invalid) return false;
    
                const is_value_invalid = value_validators.some((validator) => !validator(value[key]));
                return is_value_invalid;
              });
    
              return is_invalid;
            },
          },
        });
      };
    }
    

    你可以像这样在你的例子中使用这个装饰器

    import { isInt } from 'class-validator'
    export class CreateWarmupPlanRequestDto {
      @IsOptional()
      @IsMap([], [isInt])
      custom_warmup_plan: Map<string, number>;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-10
      • 2022-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 2020-05-20
      相关资源
      最近更新 更多