使用 class 验证器和 nestjs 验证嵌套对象
Validate nested objects using class validator and nestjs
我正在尝试使用 class-validator 和 NestJS 来验证嵌套对象。我已经尝试通过使用 class-transform 中的 @Type
装饰器来遵循此 ,但没有任何运气。这是我拥有的:
DTO:
class PositionDto {
@IsNumber()
cost: number;
@IsNumber()
quantity: number;
}
export class FreeAgentsCreateEventDto {
@IsNumber()
eventId: number;
@IsEnum(FinderGamesSkillLevel)
skillLevel: FinderGamesSkillLevel;
@ValidateNested({ each: true })
@Type(() => PositionDto)
positions: PositionDto[];
}
我也在使用内置的 nestjs 验证管道,这是我的 bootstrap:
async function bootstrap() {
const app = await NestFactory.create(ServerModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(config.PORT);
}
bootstrap();
其他属性工作正常,对象数组是唯一不工作的。
您希望 positions: [1]
抛出 400,但它被接受了。
根据这个 Github issue,这似乎是 class-validator 中的一个错误。如果您传入原始类型(boolean
、string
、number
、...)或 array
而不是对象,它将接受输入为有效的,尽管不应该。
除了创建 custom validation decorator:
之外,我没有看到任何标准的解决方法
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
export function IsNonPrimitiveArray(validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
name: 'IsNonPrimitiveArray',
target: object.constructor,
propertyName,
constraints: [],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
return Array.isArray(value) && value.reduce((a, b) => a && typeof b === 'object' && !Array.isArray(b), true);
},
},
});
};
}
然后在你的 dto 中使用它 class:
@ValidateNested({ each: true })
@IsNonPrimitiveArray()
@Type(() => PositionDto)
positions: PositionDto[];
对我来说,我可以使用 'class-transformer'
验证嵌套对象
import { Type } from 'class-transformer';
完整示例:
import {
MinLength,
MaxLength,
IsNotEmpty,
ValidateNested,
IsDefined,
IsNotEmptyObject,
IsObject,
IsString,
} from 'class-validator';
import { Type } from 'class-transformer';
class MultiLanguageDTO {
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
en: string;
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
ar: string;
}
export class VideoDTO {
@IsDefined()
@IsNotEmptyObject()
@IsObject()
@ValidateNested()
@Type(() => MultiLanguageDTO)
name!: MultiLanguageDTO;
}
我遇到了同样的问题,所以我创建了自己的 ValidateNested
装饰器。
import {
ValidationOptions,
registerDecorator,
ValidationArguments,
validateSync,
} from 'class-validator';
import { plainToClass } from 'class-transformer';
/**
* @decorator
* @description A custom decorator to validate a validation-schema within a validation schema upload N levels
* @param schema The validation Class
*/
export function ValidateNested(
schema: new () => any,
validationOptions?: ValidationOptions
) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'ValidateNested',
target: object.constructor,
propertyName: propertyName,
constraints: [],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
args.value;
if (Array.isArray(value)) {
for (let i = 0; i < (<Array<any>>value).length; i++) {
if (validateSync(plainToClass(schema, value[i])).length) {
return false;
}
}
return true;
} else
return validateSync(plainToClass(schema, value)).length
? false
: true;
},
defaultMessage(args) {
if (Array.isArray(args.value)) {
for (let i = 0; i < (<Array<any>>args.value).length; i++) {
return (
`${args.property}::index${i} -> ` +
validateSync(plainToClass(schema, args.value[i]))
.map((e) => e.constraints)
.reduce((acc, next) => acc.concat(Object.values(next)), [])
).toString();
}
} else
return (
`${args.property}: ` +
validateSync(plainToClass(schema, args.value))
.map((e) => e.constraints)
.reduce((acc, next) => acc.concat(Object.values(next)), [])
).toString();
},
},
});
};
}
然后你可以像-
一样使用它
class Schema2 {
@IsNotEmpty()
@IsString()
prop1: string;
@IsNotEmpty()
@IsString()
prop2: string;
}
class Schema1 {
@IsNotEmpty()
@IsString()
prop3: string;
@ValidateNested(Schema2)
nested_prop: Schema2;
}
适用于非原始数组和 javascript 对象。
我正在尝试使用 class-validator 和 NestJS 来验证嵌套对象。我已经尝试通过使用 class-transform 中的 @Type
装饰器来遵循此
DTO:
class PositionDto {
@IsNumber()
cost: number;
@IsNumber()
quantity: number;
}
export class FreeAgentsCreateEventDto {
@IsNumber()
eventId: number;
@IsEnum(FinderGamesSkillLevel)
skillLevel: FinderGamesSkillLevel;
@ValidateNested({ each: true })
@Type(() => PositionDto)
positions: PositionDto[];
}
我也在使用内置的 nestjs 验证管道,这是我的 bootstrap:
async function bootstrap() {
const app = await NestFactory.create(ServerModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(config.PORT);
}
bootstrap();
其他属性工作正常,对象数组是唯一不工作的。
您希望 positions: [1]
抛出 400,但它被接受了。
根据这个 Github issue,这似乎是 class-validator 中的一个错误。如果您传入原始类型(boolean
、string
、number
、...)或 array
而不是对象,它将接受输入为有效的,尽管不应该。
除了创建 custom validation decorator:
之外,我没有看到任何标准的解决方法import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
export function IsNonPrimitiveArray(validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
name: 'IsNonPrimitiveArray',
target: object.constructor,
propertyName,
constraints: [],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
return Array.isArray(value) && value.reduce((a, b) => a && typeof b === 'object' && !Array.isArray(b), true);
},
},
});
};
}
然后在你的 dto 中使用它 class:
@ValidateNested({ each: true })
@IsNonPrimitiveArray()
@Type(() => PositionDto)
positions: PositionDto[];
对我来说,我可以使用 'class-transformer'
import { Type } from 'class-transformer';
完整示例:
import {
MinLength,
MaxLength,
IsNotEmpty,
ValidateNested,
IsDefined,
IsNotEmptyObject,
IsObject,
IsString,
} from 'class-validator';
import { Type } from 'class-transformer';
class MultiLanguageDTO {
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
en: string;
@IsString()
@IsNotEmpty()
@MinLength(4)
@MaxLength(40)
ar: string;
}
export class VideoDTO {
@IsDefined()
@IsNotEmptyObject()
@IsObject()
@ValidateNested()
@Type(() => MultiLanguageDTO)
name!: MultiLanguageDTO;
}
我遇到了同样的问题,所以我创建了自己的 ValidateNested
装饰器。
import {
ValidationOptions,
registerDecorator,
ValidationArguments,
validateSync,
} from 'class-validator';
import { plainToClass } from 'class-transformer';
/**
* @decorator
* @description A custom decorator to validate a validation-schema within a validation schema upload N levels
* @param schema The validation Class
*/
export function ValidateNested(
schema: new () => any,
validationOptions?: ValidationOptions
) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'ValidateNested',
target: object.constructor,
propertyName: propertyName,
constraints: [],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
args.value;
if (Array.isArray(value)) {
for (let i = 0; i < (<Array<any>>value).length; i++) {
if (validateSync(plainToClass(schema, value[i])).length) {
return false;
}
}
return true;
} else
return validateSync(plainToClass(schema, value)).length
? false
: true;
},
defaultMessage(args) {
if (Array.isArray(args.value)) {
for (let i = 0; i < (<Array<any>>args.value).length; i++) {
return (
`${args.property}::index${i} -> ` +
validateSync(plainToClass(schema, args.value[i]))
.map((e) => e.constraints)
.reduce((acc, next) => acc.concat(Object.values(next)), [])
).toString();
}
} else
return (
`${args.property}: ` +
validateSync(plainToClass(schema, args.value))
.map((e) => e.constraints)
.reduce((acc, next) => acc.concat(Object.values(next)), [])
).toString();
},
},
});
};
}
然后你可以像-
一样使用它class Schema2 {
@IsNotEmpty()
@IsString()
prop1: string;
@IsNotEmpty()
@IsString()
prop2: string;
}
class Schema1 {
@IsNotEmpty()
@IsString()
prop3: string;
@ValidateNested(Schema2)
nested_prop: Schema2;
}
适用于非原始数组和 javascript 对象。