DI, Guards & Interceptors
Dependency Injection
// Standard injection via constructor
@Injectable()
export class OrdersService {
constructor(
private readonly usersService: UsersService,
private readonly emailService: EmailService,
private readonly configService: ConfigService,
) {}
}
// Custom provider — factory
@Module({
providers: [
{
provide: 'DATABASE_CONNECTION',
useFactory: async (config: ConfigService) => {
return createConnection(config.get('DATABASE_URL'));
},
inject: [ConfigService],
},
{
provide: 'APP_CONFIG',
useValue: { timeout: 5000, retries: 3 },
},
],
})
export class AppModule {}
// Inject custom provider
@Injectable()
export class AppService {
constructor(
@Inject('DATABASE_CONNECTION') private readonly db: Connection,
@Inject('APP_CONFIG') private readonly config: { timeout: number },
) {}
}
// ConfigModule (built-in, global)
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' }),
],
})
export class AppModule {}
// Use anywhere
constructor(private configService: ConfigService) {}
const dbUrl = this.configService.get<string>('DATABASE_URL');Guards
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const token = this.extractToken(request);
if (!token) throw new UnauthorizedException();
try {
const payload = await this.jwtService.verifyAsync(token);
request['user'] = payload; // attach to request
return true;
} catch {
throw new UnauthorizedException();
}
}
private extractToken(req: Request): string | null {
const [type, token] = req.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : null;
}
}
// Role-based guard using custom decorator
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
if (!requiredRoles) return true;
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some(role => user.roles?.includes(role));
}
}
// Custom decorator
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
// Applying guards
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('admin-only')
adminRoute() { ... }
// Global guard
app.useGlobalGuards(new JwtAuthGuard(jwtService));Interceptors
import {
CallHandler, ExecutionContext, Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
// Transform response — wrap in { data: ... }
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map(data => ({ data, success: true })));
}
}
// Logging interceptor
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const req = context.switchToHttp().getRequest();
const start = Date.now();
console.log(`--> ${req.method} ${req.url}`);
return next.handle().pipe(
tap(() => console.log(`<-- ${req.method} ${req.url} ${Date.now() - start}ms`)),
);
}
}
// Apply
@UseInterceptors(TransformInterceptor)
@Get()
findAll() { ... }
// Global
app.useGlobalInterceptors(new TransformInterceptor());Pipes & Custom Decorators
// Built-in pipes
@Param('id', ParseIntPipe) id: number
@Param('id', ParseUUIDPipe) id: string
@Body(new ValidationPipe()) dto: CreateUserDto
// Custom pipe
@Injectable()
export class TrimPipe implements PipeTransform {
transform(value: any) {
if (typeof value === 'string') return value.trim();
return value;
}
}
// Custom param decorator
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data: string | undefined, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return data ? request.user?.[data] : request.user;
},
);
// Usage
@Get('profile')
getProfile(@CurrentUser() user: UserPayload) {
return user;
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free