Pipes
⭐ Interview Importance: HIGH
⏱️ Revision Time: 14 min
Pipes operate on the arguments being processed by a controller route handler. They intercept method invocations just before they are executed.
Overview
A pipe is a class annotated with the @Injectable() decorator, which implements the PipeTransform interface.
Pipes have two typical use cases in NestJS:
- Transformation: transform input data to the desired form (e.g., from a string to an integer).
- Validation: evaluate input data and, if valid, simply pass it through unchanged; otherwise, throw an exception.
In both cases, pipes operate on the arguments being processed by a controller route handler. Nest interposes a pipe just before a method is invoked, and the pipe receives the arguments destined for the method.
Key Concepts
PipeTransformInterface: Every pipe must implement this interface, which mandates thetransform()method.- Auto-Exception Handling: If a pipe throws an error (like
BadRequestException), NestJS automatically catches it and returns a formatted JSON error response to the client. The controller method is completely skipped. - Execution Context: Pipes are executed after Middleware, Guards, and Interceptors, but right before the Controller method.
Code Examples
How Pipes are Applied
Pipes are most commonly used in conjunction with the @Body(), @Query(), and @Param() decorators.
import { Controller, Get, Param, ParseIntPipe, Body, ValidationPipe } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UsersController {
// 1. TRANSFORMATION: Converting the string 'id' into a number
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return `Finding user with ID ${id}`;
}
// 2. VALIDATION: Validating the payload against a DTO
@Post()
create(@Body(new ValidationPipe()) createUserDto: CreateUserDto) {
return 'This only executes if createUserDto is valid!';
}
}
Passing Classes vs Instances
You can pass the pipe class itself, or an instance of the pipe.
// Passing the class leaves instantiation up to NestJS (Recommended, uses less memory)
@Param('id', ParseIntPipe) id: number
// Passing an instance allows you to customize the pipe's behavior
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE })) id: number
Best Practices
- Global Pipes for Validation: Instead of manually applying
ValidationPipeto every single@Body()in your app, apply it globally in yourmain.tsfile usingapp.useGlobalPipes(new ValidationPipe()). - Don’t Trust User Input: Always use
ParseIntPipeorParseUUIDPipefor@Paramand@Queryvariables that you expect to be numbers or UUIDs. Without them, you are vulnerable to bugs and potential injection attacks because URL parameters are always strings by default.