So at first I quickly opened the docs and started looking up for advance usage and I came to know that custom decorator would definitely help me and it did using bellow example.
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;
}
So with the above example I'm successfully able to validate value
by type
, but still I'm unable to customize the error message based on the type
😭.
😢 So after a day of research I lose all my hope and decided to use another library for this complex validation and I did so but there was a drawback with that library and I ended up coming back to the class-validator
and after a lot of research I found a way to customize the error message based on the type
.
So here is the code for customizing error message based on the type
and I used defaultMessage()
to customize it.
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!';
}
},
},
});
};
}
🤗 And finally it's done!