Careeroza
Binding Scopes
Global, Controller and Method Level
Guards, interceptors, pipes and filters can be bound at three levels. Global ones run first, then controller-level, then method-level (filters are the opposite: the most specific filter is tried first).
src/orders/orders.controller.ts
import { Body, Controller, Post, UseFilters, UseGuards, UseInterceptors, UsePipes, ValidationPipe } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { TimingInterceptor } from '../common/timing.interceptor';
import { PaymentErrorFilter } from './payment-error.filter';
import { CreateOrderDto } from './dto/create-order.dto';
@Controller('orders')
@UseGuards(JwtAuthGuard) // controller level: every route
@UseInterceptors(TimingInterceptor)
export class OrdersController {
@Post()
@UsePipes(new ValidationPipe({ whitelist: true })) // method level
@UseFilters(PaymentErrorFilter)
create(@Body() dto: CreateOrderDto) {
return dto;
}
}Global Binding with DI
app.useGlobalGuards(new X()) in main.ts works, but the class is created outside the DI container, so it cannot inject services. Register globals as providers instead:
src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { RolesGuard } from './auth/roles.guard';
import { TimingInterceptor } from './common/timing.interceptor';
import { AllExceptionsFilter } from './common/all-exceptions.filter';
@Module({
providers: [
{ provide: APP_GUARD, useClass: JwtAuthGuard }, // order of APP_GUARD entries = run order
{ provide: APP_GUARD, useClass: RolesGuard },
{ provide: APP_INTERCEPTOR, useClass: TimingInterceptor },
{ provide: APP_PIPE, useValue: new ValidationPipe({ whitelist: true, transform: true }) },
{ provide: APP_FILTER, useClass: AllExceptionsFilter },
],
})
export class AppModule {}