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();