class-validator 带有自定义错误消息的关系验证
class-validator relational validation with custom error messages
所以我正在构建一个 API,用户在请求正文中给我们 type
和 value
,type
可能是 CNIC, EMAIL, MOBILE
现在基于 type
我必须验证值,例如 EMAIL
是否有效或 MOBILE
是否有效等
因此我们可以看到 value
字段依赖于 type
字段来验证它。
我需要一种使用 class-validator
validationPipe
.
来处理这个问题的方法
所以起初我快速打开文档并开始查找高级用法,我开始知道自定义装饰器肯定会帮助我并且它确实使用了下面的示例。
validate-value-by-type.decorator.ts
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
isEmail,
} from 'class-validator';
import { CA_DetailsTypes } from './models';
export function ValidateByAliasType(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'validateByAliasType',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
if (relatedValue === CA_DetailsTypes.EMAIL) {
return isEmail(value) && value.length > 5 && value.length <= 99;
}
if (relatedValue === CA_DetailsTypes.CNIC) {
return value.length === 13;
}
if (relatedValue === CA_DetailsTypes.MOBILE) {
return value.length === 11;
}
if (relatedValue === CA_DetailsTypes.TXT) {
return value.length > 3 && value.length <= 99;
}
return false;
},
},
});
};
}
client.request.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty } from 'class-validator';
export enum CA_DetailsTypes {
'CNIC' = 'CNIC',
'MOBILE' = 'MOBILE',
'EMAIL' = 'EMAIL',
'TXT' = 'TXT',
}
export class CA_FetchDetails_DTO {
@ApiProperty({
example: 'MOBILE',
type: 'enum',
enum: CA_DetailsTypes,
})
@IsNotEmpty()
@IsEnum(CA_DetailsTypes)
type: CA_DetailsTypes;
@ApiProperty({ example: '03070000002' })
@ValidateByAliasType('type')
value: string;
}
因此,对于上面的示例,我可以通过 type
成功验证 value
,但我仍然无法根据 type
自定义错误消息。
所以经过一天的研究,我失去了所有的希望,决定使用另一个库来进行这个复杂的验证,我这样做了,但是那个库有一个缺点,我最终回到了 class-validator
经过大量研究,我找到了一种基于 type
.
自定义错误消息的方法
所以这里是基于type
自定义错误消息的代码,我使用defaultMessage()
来自定义它。
validate-value-by-type.decorator.ts
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
isEmail,
} from 'class-validator';
import { CA_DetailsTypes } from './models';
export function ValidateByAliasType(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'validateByAliasType',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
if (relatedValue === CA_DetailsTypes.EMAIL) {
return isEmail(value) && value.length > 5 && value.length <= 99;
}
if (relatedValue === CA_DetailsTypes.CNIC) {
return value.length === 13;
}
if (relatedValue === CA_DetailsTypes.MOBILE) {
return value.length === 11;
}
if (relatedValue === CA_DetailsTypes.TXT) {
return value.length > 3 && value.length <= 99;
}
return false;
},
defaultMessage(args?: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
switch (relatedValue) {
case CA_DetailsTypes.EMAIL:
return 'Please enter valid email!';
case CA_DetailsTypes.MOBILE:
return 'Please enter valid mobile!';
case CA_DetailsTypes.CNIC:
return 'Please enter valid CNIC!';
default:
return 'Invalid value!';
}
},
},
});
};
}
终于完成了!
所以我正在构建一个 API,用户在请求正文中给我们 type
和 value
,type
可能是 CNIC, EMAIL, MOBILE
现在基于 type
我必须验证值,例如 EMAIL
是否有效或 MOBILE
是否有效等
因此我们可以看到 value
字段依赖于 type
字段来验证它。
我需要一种使用 class-validator
validationPipe
.
所以起初我快速打开文档并开始查找高级用法,我开始知道自定义装饰器肯定会帮助我并且它确实使用了下面的示例。
validate-value-by-type.decorator.ts
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
isEmail,
} from 'class-validator';
import { CA_DetailsTypes } from './models';
export function ValidateByAliasType(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'validateByAliasType',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
if (relatedValue === CA_DetailsTypes.EMAIL) {
return isEmail(value) && value.length > 5 && value.length <= 99;
}
if (relatedValue === CA_DetailsTypes.CNIC) {
return value.length === 13;
}
if (relatedValue === CA_DetailsTypes.MOBILE) {
return value.length === 11;
}
if (relatedValue === CA_DetailsTypes.TXT) {
return value.length > 3 && value.length <= 99;
}
return false;
},
},
});
};
}
client.request.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty } from 'class-validator';
export enum CA_DetailsTypes {
'CNIC' = 'CNIC',
'MOBILE' = 'MOBILE',
'EMAIL' = 'EMAIL',
'TXT' = 'TXT',
}
export class CA_FetchDetails_DTO {
@ApiProperty({
example: 'MOBILE',
type: 'enum',
enum: CA_DetailsTypes,
})
@IsNotEmpty()
@IsEnum(CA_DetailsTypes)
type: CA_DetailsTypes;
@ApiProperty({ example: '03070000002' })
@ValidateByAliasType('type')
value: string;
}
因此,对于上面的示例,我可以通过 type
成功验证 value
,但我仍然无法根据 type
自定义错误消息。
所以经过一天的研究,我失去了所有的希望,决定使用另一个库来进行这个复杂的验证,我这样做了,但是那个库有一个缺点,我最终回到了 class-validator
经过大量研究,我找到了一种基于 type
.
所以这里是基于type
自定义错误消息的代码,我使用defaultMessage()
来自定义它。
validate-value-by-type.decorator.ts
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
isEmail,
} from 'class-validator';
import { CA_DetailsTypes } from './models';
export function ValidateByAliasType(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'validateByAliasType',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
if (relatedValue === CA_DetailsTypes.EMAIL) {
return isEmail(value) && value.length > 5 && value.length <= 99;
}
if (relatedValue === CA_DetailsTypes.CNIC) {
return value.length === 13;
}
if (relatedValue === CA_DetailsTypes.MOBILE) {
return value.length === 11;
}
if (relatedValue === CA_DetailsTypes.TXT) {
return value.length > 3 && value.length <= 99;
}
return false;
},
defaultMessage(args?: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
switch (relatedValue) {
case CA_DetailsTypes.EMAIL:
return 'Please enter valid email!';
case CA_DetailsTypes.MOBILE:
return 'Please enter valid mobile!';
case CA_DetailsTypes.CNIC:
return 'Please enter valid CNIC!';
default:
return 'Invalid value!';
}
},
},
});
};
}
终于完成了!