Interceptors let you run code before and after method calls, so you can add shared features like logging or timing without changing each method.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class TimingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const start = Date.now(); return next.handle().pipe( tap(() => console.log(`Execution time: ${Date.now() - start}ms`)) ); } }
The interceptor uses tap to log after the method finishes, but it does not modify the response data.
The intercept method runs before and after the controller method, allowing it to modify or observe the process.
The Express response object uses setHeader to add headers. Other methods like setHeaders do not exist or are incorrect.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class SilentInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const start = Date.now(); next.handle().subscribe(() => { console.log(`Execution time: ${Date.now() - start}ms`); }); return next.handle(); } }
Calling next.handle() twice creates two separate observables. The subscription inside intercept is ignored because the returned observable is different. Using tap inside the pipe ensures the side effect runs on the same observable.
