This is a follow-up post to my previous blog NestJS Payload Validation. In this blog-post I’ll talk about how we can implement our own custom payload validation. That is, there might be a scenario where you would like to add your own logic to validate particular payload value and the class-validator package provides us with this ability.
Before we begin, here's the github repo for the project
which has below mentioned code examples.
In order to perform custom payload validation we need to implement ValidatorConstraintInterface
interface and its validate
method and post implementing the interface we need to apply @ValidatorConstraint
decorator to the class (which implements the interface). For instance, lets say we have deployed an api which expects payload with employee’s age information, here’s an example:
{
"age": 24
}
And the DTO for the same:
export class EmployeeAgeDetails {
age: number;
}
The age
property needs to have some restriction, like for instance, age should be an integer value and should be greater than (>=) 18 and less than (<=) 65.
I know in real world we would expect much more info than just employee’s age, but lets keep things simple so we understand better and quicker!
Fyi, we can perform the above mention validation directly with validation decorators provided by the class-validator as well. Please checkout my NestJS Payload Validation blog for example.
Lets see some code examples to demonstrate above case:
The class which implements ValidatorConstraintInterface
interface, lets call it CustomAgeLimitValidator
, here’s code for the same:
import {
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
@ValidatorConstraint({ name: 'CustomAgeLimitValidator', async: false })
export class CustomAgeLimitValidator implements ValidatorConstraintInterface {
validate(value: any): boolean {
// Add validation logic here
if (value < 18 || value > 65) return false;
return true;
}
}
The name
argument in @ValidatorConstraint
decorator represents the ‘error type’ and if not provided, the value will be generated automatically. The validation can also be asynchronous, hence the param async
is used in decorator @ValidatorConstraint
(please checkout the documentation for more info).
Here’s how you apply the CustomAgeLimitValidator
validator to EmployeeAgeDetails
DTO:
import {
IsInt,
IsNotEmpty,
Validate,
} from 'class-validator';
import { CustomAgeLimitValidator } from '../custome-payload-validators/age-limit-validator';
export class EmployeeAgeDetails {
@IsNotEmpty()
@IsInt()
@Validate(CustomAgeLimitValidator)
age: number;
}
The validation decorators provided by the class-validator provides us with the ability to pass our own error message. In our case, here’s how we will do it:
@Validate(CustomAgeLimitValidator, {message: 'Age limit violation! Employee age should be between 18 and 65 years'})
With these changes if we try to feed our endpoint with below payload:
{
"age": 16
}
It would cause below error:
{
"statusCode": 400,
"message": [
"Age limit violation! Employee age should be between 18 and 65 years"
],
"error": "Bad Request"
}
Along with the ability to provide error message while applying validation decorators we can also provide default error message incase we forget or don’t feel the need to provide error message while applying decorator. To implement this case, we need to add optional defaultMessage
method inside our CustomAgeLimitValidator
class. Here’s the code example:
import {
ValidatorConstraint,
ValidatorConstraintInterface,
ValidationArguments,
} from 'class-validator';
@ValidatorConstraint({ name: 'CustomAgeLimitValidator', async: false })
export class CustomAgeLimitValidator implements ValidatorConstraintInterface {
validate(value: any): boolean {
// Add validation logic here
if (value < 18 || value > 65) return false;
return true;
}
// optional method
defaultMessage(args: ValidationArguments) {
// Provide default error message if validation failed
return `Age value ${args.value} caused age limit violated! Employee age should be between 18 and 65 years`;
}
}
And if we feed the api with invalid age value
{
"age": 16
}
with above changes, the output error message would be:
{
"statusCode": 400,
"message": [
"Age value 16 caused age limit violation! Employee age should be between 18 and 65 years"
],
"error": "Bad Request"
}
And we are done! Hope you guys enjoyed it.
Top comments (0)