Objective
The main objective of this article is showing how to generate custom error object when the validation fails, but we will go through the process of using class-validator and later about generating custom error object.
What is class-validator
class-validator allows use of decorator and non-decorator based validation. Internally uses validator.js to perform validation. class-validator works on both browser and node.js platforms.
How to use it
In order to use class-validator in nest.js we need to install class-validator and class-transformer.
npm i --save class-validator class-transformer
To configure, in main.ts
file we need to invoke ValidationPipe()
constructor function imported form @nestjs/common
and pass it as a argument for app.useGlobalPipes
method.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ stopAtFirstError: true }));
await app.listen(3500);
}
bootstrap();
{ stopAtFirstError: true }
is just an optional argument to stop after getting the first error and return it. we can always customize it.
Let us assume we have a users
resource. We need a create create-user.dto.ts
file inside a dto
folder under users
resource as in image given below.
Inside create-user.dto.ts
file add the class validation you need to add. Refer class-validator docs for which validation you need to apply. docs: https://www.npmjs.com/package/class-validator
This is my create-user.dto.ts
file
import {
IsNotEmpty,
IsString,
MinLength,
IsAlpha,
Matches,
IsEnum,
} from 'class-validator';
export enum UserState {
ACTIVE = 'Active',
IN_ACTIVE = 'Inactive',
}
export class CreateUserDto {
@IsNotEmpty()
@IsString()
@IsAlpha()
@MinLength(1)
readonly firstName: string;
@IsNotEmpty()
@IsString()
readonly lastName: string;
@IsNotEmpty()
@IsString()
@IsNotEmpty()
@Matches(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,3}$/g)
readonly email: string;
@IsNotEmpty()
@IsString()
@Matches(/^[6789]\d{9}$/)
readonly phoneNumber: string;
@IsNotEmpty()
@IsString()
@MinLength(3)
readonly companyName: string;
@IsEnum(UserState)
readonly userState: UserState;
}
Next import CreateUserDto
class and use it inside the user controller.
import { Controller, Post, Body } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() user: CreateUserDto) {
return this.usersService.create(user);
}
}
After sending request in postman or any other api testing application this will automatically validate and send error message as shown below
Request body
{
"firstName":"",
"lastName":"K Joy",
"email":"Nn@gail.com",
"phoneNumber":"9160000000",
"companyName":"abcgf",
"userState":"Active"
}
Response
{
"statusCode": 400,
"message": [
"firstName must be longer than or equal to 1 characters"
],
"error": "Bad Request"
}
How to generate custom error message object
But we need to get which property just gave us this error along with the error message. In order to do that we need to configure the ValidationPipe()
in main.ts
file with some configurations.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe, BadRequestException } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
exceptionFactory: (errors) => {
const result = errors.map((error) => ({
property: error.property,
message: error.constraints[Object.keys(error.constraints)[0]],
}));
return new BadRequestException(result);
},
stopAtFirstError: true,
}),
);
await app.listen(3500);
}
bootstrap();
Let me break down the above code. The object below is the error object.
{
property: 'firstName',
children: [],
constraints: {
minLength: 'firstName must be longer than or equal to 1 characters'
}
}
property: error.property
usage is straight forward.
message
is basically the value inside the the constraints object. But the key for the constraint object (here minLength
) is not static. The key will be different for different validation failure.
Object.keys(error.constraints)[0]
Object.keys just changes all object keys to array and we access the first key by [0]
.
Request body
{
"firstName":"",
"lastName":"K Joy",
"email":"Nn@gail.com",
"phoneNumber":"9160000000",
"companyName":"abcgf",
"userState":"Active"
}
Response
{
"statusCode": 400,
"message": [
{
"property": "firstName",
"message": "firstName must be longer than or equal to 1 characters"
}
],
"error": "Bad Request"
}
If you found this helpful, be sure to leave a 💖 on the post. Thank you!
Top comments (9)
Thanks alot, custom error message is what I'm looking for :)
You're welcome
I recommend using 422 UNPROCESSABLE ENTITY for validation errors.
i need to custom like this
{
"statusCode": 400,
"message": "firstName must be longer than or equal to 1 characters"
}
any idea please
Tks sir
Thanks alot, can u share a github link to this project
great job man! thanks from brazil
This really saves me, thanks!
Amazing! Thanks!