For example we have a rest endpoint, we need to validate the data we receive in correct format:
import { IsMongoId, IsString, IsBoolean, IsInt } from "class-validator"; export class Course { @IsString() @IsMongoId() _id: string; @IsInt({ message: "seqNo must be numeric" }) seqNo: number; // always false, no need to be always applied the rule @IsString({ always: false }) url: string; @IsString() iconUrl: string; @IsString() courseListIcon: string; @IsString() description: string; @IsString() longDescription: string; @IsString() category: string; @IsInt() lessonsCount: number; @IsBoolean() promo: boolean; }
We can use ValidationPipe to ensure all the endpoint receive the correct data:
import { Controller, Get, Param, Put, Body, Delete, Post, BadRequestException, UseFilters, } from '@nestjs/common'; import { Course } from '../../../../shared/course'; import { CoursesRepository } from '../repositories/courses.repository'; @Controller('courses') export class CoursesController { constructor(private couresDB: CoursesRepository) {} @Post() async createCourse(@Body() course: Course): Promise<Course> { return this.couresDB.addCourse(course); }
... }
Use global filter:
import { BadRequestException } from '@nestjs/common'; export class ValidationException extends BadRequestException { constructor(public validationErrors: string[]) { super(); } } ----
import { Catch, ExceptionFilter, ArgumentsHost } from '@nestjs/common'; import { ValidationException } from './validation.exception'; @Catch(ValidationException) export class ValidationFilter implements ExceptionFilter { catch(exception: any, host: ArgumentsHost): any { const ctx = host.switchToHttp(), response = ctx.getResponse(); return response.status(400).json({ statusCode: 400, createdBy: 'ValidationFilter', validationErrors: exception.validationErrors, }); } }
main.ts:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './filters/http-exception.filter'; import { FallbackExpectionFilter } from './filters/fallback.filter'; import * as mongoose from 'mongoose'; import { ValidationPipe, ValidationError } from '@nestjs/common'; import { ValidationFilter } from './filters/validation.filter'; import { ValidationException } from './filters/validation.exception'; mongoose.set('useFindAndModify', false); async function bootstrap() { const app = await NestFactory.create(AppModule); app.setGlobalPrefix('api'); // order matters app.useGlobalFilters( new FallbackExpectionFilter(), new HttpExceptionFilter(), new ValidationFilter(), ); app.useGlobalPipes( new ValidationPipe({ skipMissingProperties: true, // trigger when validation error occur exceptionFactory: (errors: ValidationError[]) => { const message = errors.map( error => `${error.property} has wrong value ${error.value}, ${Object.values( error.constraints, ).join(', ')}`, ); return new ValidationException(message); }, }), ); await app.listen(9000); } bootstrap();