How to use class-validator and generate custom error object in nest.js
Tags: javascript, nest, classvalidator, typescript
Published: 2023-06-06 06:43:36

##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.

```javascript
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.


![main.ts file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc7sizcu7az9jgn8nceu.jpeg)

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.


![create-user.to.ts file location](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po2asbq0bu2w2hzkrw9f.jpeg)
  


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
```javascript
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. 
```javascript
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
```javascript
{
  "firstName":"",
  "lastName":"K Joy",
  "email":"Nn@gail.com",
  "phoneNumber":"9160000000",
  "companyName":"abcgf",
  "userState":"Active"
}
```

Response
```javascript
{
  "statusCode": 400,
  "message": [
    "firstName must be longer than or equal to 1 characters"
  ],
  "error": "Bad Request"
}
```


![image of a non customized class-validator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qg6ne2tzi2gqmtolmul0.jpeg)

##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. 
```javascript
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.
```javascript
{
  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
```javascript
{
  "firstName":"",
  "lastName":"K Joy",
  "email":"Nn@gail.com",
  "phoneNumber":"9160000000",
  "companyName":"abcgf",
  "userState":"Active"
}
```

Response
```javascript
{
  "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!