Pipes
⭐ Interview Importance: HIGH
⏱️ Revision Time: 6 min
Pipes are classes annotated with the @Injectable() decorator that implement the PipeTransform interface. They operate on the arguments being processed by a route handler.
Overview
Pipes have two typical use cases in NestJS:
- Transformation: Transform input data to the desired form (e.g., parsing a string to an integer).
- Validation: Evaluate input data and if valid, simply pass it through unchanged; otherwise, throw an exception.
Pipes run inside the exceptions zone. This means that if a Pipe throws an exception (like a BadRequestException for invalid data), the exception layer (Exception Filters) catches it automatically, and the route handler is never executed.
Key Concepts
- Built-in Pipes: Nest comes with several built-in pipes out of the box (e.g.,
ValidationPipe,ParseIntPipe,ParseBoolPipe,ParseUUIDPipe). - Binding Pipes: Pipes can be bound globally, at the controller level, at the method level, or at the parameter level.
class-validatorintegration: The built-inValidationPipeworks seamlessly with theclass-validatorandclass-transformerlibraries to validate incoming JSON payloads against DTO classes.
Code Examples
Transformation (ParseIntPipe)
Using a built-in pipe to ensure a route parameter is converted to a JavaScript number.
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
// 'id' is guaranteed to be a number here.
// If the user passes GET /users/abc, ParseIntPipe throws a 400 Bad Request
return this.usersService.findOne(id);
}
}
Validation (Using ValidationPipe and DTOs)
This is the most common use of pipes in NestJS.
1. Create the DTO with validation decorators:
import { IsString, IsInt, Min, Max } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsInt()
@Min(18)
@Max(100)
age: number;
}
2. Enable the pipe globally (in main.ts):
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable validation globally
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
await app.listen(3000);
}
3. Use the DTO in the Controller:
@Post()
create(@Body() createUserDto: CreateUserDto) {
// If the payload is invalid, a 400 response is returned automatically.
return this.usersService.create(createUserDto);
}
Best Practices
- Use
ValidationPipeglobally: You almost always want to validate incoming payloads. Bind theValidationPipeglobally in yourmain.tsrather than adding it to every controller. - Use
whitelist: true: When configuring theValidationPipe, pass{ whitelist: true }. This will automatically strip any properties from the incoming JSON that do not have any decorators in the DTO, preventing injection of malicious unexpected properties. - Fail Fast: Pipes are the perfect place to “fail fast”. If the input is wrong, throw a 400 error before the controller or service logic even begins.