Add safety and reliability using validation, pipes, and custom error handling mechanisms.
Welcome to the chapter on Data Validation with Pipes! In this section, we'll explore how to effectively use class-validator and class-transformer to validate and transform incoming request data in your NestJS applications. We'll cover everything from using built-in pipes to creating custom ones, and discuss best practices for handling validation errors.
In NestJS, a pipe is a middleware-like feature that allows you to manipulate the request data before it reaches your controller. Pipes can be used for tasks like validation, sanitization, and transformation of incoming data.
NestJS comes with several built-in pipes that you can use out of the box. One of the most commonly used is the ValidationPipe, which is designed to validate request data against a set of defined constraints.
import { ValidationPipe } from '@nestjs/common';
// Global validation configuration
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
validateCustomDecorators: true,
})
);
Data Transfer Objects (DTOs) are a great way to define the structure of your request data. By using class-validator decorators, you can easily validate incoming data against these DTOs.
@nestjs/common
import { IsString, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(5)
username: string;
@IsString()
password: string;
}
If the built-in pipes don't meet your needs, you can easily create custom pipes. This allows you to define specific validation logic that's unique to your application.
import { PipeTransform } from '@nestjs/common';
export class CustomValidationPipe implements PipeTransform {
transform(value: any) {
// Add custom validation logic here
if (value.somethingInvalid) {
throw new Error('Invalid data');
}
return value;
}
}
Pipes can be applied in two ways: globally (applies to all routes) or per route (only applies to specific endpoints). Global pipes are useful for common validations, while route-specific pipes allow for more granular control.
// Global pipe configuration
app.useGlobalPipes(new ValidationPipe());
// Route-specific pipe usage
@Post()
@UsePipes(new CustomValidationPipe())
create(@Body() createUserDto: CreateUserDto) {
// ...
}
One of the biggest mistakes developers make is skipping validation for external or user-provided data. Always ensure that any data coming into your application is properly validated to prevent security issues and unexpected behavior.
Pipes are invaluable in real-world applications for tasks like sanitizing user input, validating API requests, and transforming data into a format that your business logic can easily work with. By properly implementing pipes, you can ensure that your application is both robust and maintainable.
Welcome to the chapter on Global Exception Filters & Custom Errors! Handling errors is a critical part of building robust applications. In this section, we'll explore how to manage exceptions in your NestJS application using global and custom exception filters.
An exception filter is a mechanism that intercepts exceptions thrown within your application and provides a standardized way to handle them. NestJS provides both built-in filters and the ability to create custom ones.
Global exception filters are registered at the application level and apply to all routes. They provide a centralized way to handle errors across your entire application.
import { Catch, ExceptionFilter } from '@nestjs/common';
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown) {
console.error('Global exception caught:', exception);
// Handle the exception and send a response
}
}
// Register the filter in your main.ts
app.useGlobalFilters(new GlobalExceptionFilter());
You can create custom filters to handle specific types of exceptions. This is useful for providing meaningful error messages and maintaining consistent API responses.
import { Catch, ArgumentsHost } from '@nestjs/common';
@Catch(ForbiddenException)
export class ForbiddenFilter {
catch(exception: ForbiddenException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(403).json({
statusCode: 403,
message: 'Forbidden resource',
});
}
}
Imagine you're building an e-commerce platform. You could use exception filters to handle scenarios like: - Invalid payment methods - Out-of-stock items - Unauthorized access attempts Each of these scenarios would have its own custom filter and response.
Question 1 of 10