Search code examples
javascriptnestjsclass-validatorserver-side-validation

Validation does not work with Partial<DTO> - NestJS


I want to apply server-side validation on my CRUD API. The entity in question is called Employee. I am using an employee.dto (shown below) for the create and update endpoints.

The class-validator package works fine on the create method but ignores all rules in the DTO when I use it with Partial<EmployeeDTO> in the update method.

Please use the code below for reference.

Packages

"class-transformer": "^0.2.3",
"class-validator": "^0.10.0",

Employee DTO

import { IsString, IsNotEmpty, IsEmail, IsEnum } from 'class-validator';

import { EmployeeRoles } from '../../entities/employee.entity';

export class EmployeeDTO {
  @IsString()
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  password: string;

  @IsString()
  @IsNotEmpty()
  username: string;

  @IsString()
  @IsNotEmpty()
  fullName: string;

  @IsString()
  @IsNotEmpty()
  @IsEnum(EmployeeRoles)
  role: string;
}

Employee Controller

import {
  Controller,
  Param,
  Post,
  Body,
  Put,
  UsePipes,
} from '@nestjs/common';

import { EmployeeDTO } from './dto/employee.dto';
import { EmployeeService } from './employee.service';
import { ValidationPipe } from '../shared/pipes/validation.pipe';

@Controller('employee')
export class EmployeeController {
  constructor(private employeeService: EmployeeService) {}

  @Post()
  @UsePipes(ValidationPipe)
  addNewEmployee(@Body() data: EmployeeDTO) {
    return this.employeeService.create(data);
  }

  @Put(':id')
  @UsePipes(ValidationPipe)
  updateEmployee(@Param('id') id: number, @Body() data: Partial<EmployeeDTO>) {
    return this.employeeService.update(id, data);
  }
}

Possible Solution

I work around I can think of is creating separate DTOs for create and update methods, but I don't like the idea of repeating the code.


Solution

  • For this answer, I'll take a guess and assume that you use the ValidationPipe provided in the NestJS' documentation, or a close derivative.

    Your updateEmployee method's argument data type is Partial, which doesn't emit any type metadata. for the ValidationPipe to instantiate it using the class-transformer module, resulting in the class-validator module to validate a plain object, and not an EmployeeDTO.

    For the validation to work, the type of the data argument should be a class. You could either make separate DTOs to create and update your entity, or use validation groups if you want to keep a single class.