'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 1:[1]
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.
Solution 2:[2]
In order to achieve partial validation, you can use PartialType
utility function. You can read about it here:
https://docs.nestjs.com/openapi/mapped-types#partial
You would need to create another class:
export class UpdateEmployeeDTO extends PartialType(EmployeeDTO) {}
and then in your controller, you need to replace the type of @Body data Partial<EmployeeDTO>
to UpdateEmployeeDto
. It should look like this:
@Patch(':id')
@UsePipes(ValidationPipe)
updateEmployee(@Param('id') id: number, @Body() data: UpdateEmployeeDTO) {
return this.employeeService.update(id, data);
}
Please keep in mind that you should import PartialType
from @nestjs/mapped-types
not from @nestjs/swagger
like suggested in the documentation. More about this can be found here
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Thibault Burger |
Solution 2 |