Lesson 14-NestJS Validation

Installing Dependencies

First, ensure the necessary dependency packages are installed:

npm install class-validator class-transformer

Configuring Global Pipeline

You can configure the global ValidationPipe in your main.ts or app.module.ts file:

// main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // Configure ValidationPipe globally
  app.useGlobalPipes(
    new ValidationPipe({
      // Automatically validate incoming data
      whitelist: true, // Strip unneeded properties
      forbidNonWhitelisted: true, // Prohibit undeclared properties
      transform: true, // Transform payload objects
      transformOptions: {
        enableImplicitConversion: true, // Enable explicit conversion
      },
      forbidUnknownValues: true, // Prohibit unknown values
      errorHttpStatusCode: 400, // Error status code
      disableErrorMessages: true, // Disable detailed error messages
    }),
  );
  await app.listen(3000);
}
bootstrap();

Creating DTO Class

Define a DTO (Data Transfer Object) class to represent the structure of your request body:

// src/users/dto/create-user.dto.ts
import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @MinLength(8)
  @MaxLength(20)
  password: string;
}

Using DTO Class

Use the DTO class in a controller to validate and transform the request body:

// src/users/users.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UsersController {
  @Post()
  async createUser(@Body() createUserDto: CreateUserDto) {
    // Since ValidationPipe has validated the data, createUserDto is safe and transformed
    console.log(createUserDto);
    // Here you can call a service method to save the user
  }
}

Mapping Types

If you need to map the DTO type to another type, you can perform the conversion in the service layer:

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';

@Injectable()
export class UsersService {
  async createUser(createUserDto: CreateUserDto) {
    // Map the DTO to another type here
    const user = {
      email: createUserDto.email,
      password: createUserDto.password,
      // Add other fields
    };
    // Save the user
  }
}

Parsing and Validating Arrays

To validate and parse arrays, you can use the Array type in the DTO:

// src/users/dto/create-user.dto.ts
import { IsEmail, IsNotEmpty, ValidateNested, ArrayMaxSize, ArrayMinSize } from 'class-validator';
import { Type } from 'class-transformer';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @MinLength(8)
  @MaxLength(20)
  password: string;

  @ArrayMinSize(1)
  @ArrayMaxSize(5)
  @ValidateNested({ each: true })
  @Type(() => TagDto)
  tags: TagDto[];
}

export class TagDto {
  @IsNotEmpty()
  name: string;
}

Using Array DTO in Controller

You can use the array DTO in a controller like this:

// src/users/users.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UsersController {
  @Post()
  async createUser(@Body() createUserDto: CreateUserDto) {
    console.log(createUserDto);
  }
}
  • Automatic Validation: By using ValidationPipe, you can automatically validate incoming data against the rules defined in the DTO.
  • Disabling Detailed Errors: Setting disableErrorMessages to true prevents detailed error messages from being returned to the client, which is beneficial for security.
  • Stripping Performance: Setting whitelist to true ensures only properties declared in the DTO are retained, improving performance and reducing memory usage.
  • Transforming Payload Objects: Setting transform to true allows ValidationPipe to convert incoming objects to the DTO type, eliminating the need for manual conversion.
  • Explicit Conversion: Setting transformOptions.enableImplicitConversion to true enables implicit conversions, such as converting strings to numbers.
Share your love