An interceptor lets you run code before or after a request in NestJS. It helps you change or log data easily.
Interceptor interface in NestJS
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class MyInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { // code before request return next.handle().pipe( map(data => { // code after request return data; }), ); } }
The intercept method runs for each request.
Use next.handle() to continue the request and get the response as an Observable.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { console.log('Before handling request'); return next.handle(); } }
data key.import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class TransformInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe( map(data => ({ data })), ); } }
This example shows a controller with a TimingInterceptor. It measures how long the request takes and adds that info to the response.
import { Controller, Get, UseInterceptors, Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() class TimingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const now = Date.now(); return next.handle().pipe( map(data => { const timeTaken = Date.now() - now; return { data, timeTaken: `${timeTaken}ms` }; }), ); } } @Controller('hello') @UseInterceptors(TimingInterceptor) export class HelloController { @Get() getHello() { return 'Hello World!'; } }
Interceptors work with Observables, so you can use RxJS operators to change data.
Always call next.handle() to continue the request cycle.
You can apply interceptors globally, per controller, or per route.
Interceptors let you run code before and after requests.
They help with logging, transforming data, and measuring time.
Use the intercept method and return next.handle() with optional RxJS operators.
Practice
Solution
Step 1: Understand the role of interceptors
Interceptors in NestJS are designed to execute code before and after the main request handler runs.Step 2: Compare with other options
Database schemas, routing, and authentication are handled by other parts of NestJS, not interceptors.Final Answer:
To run code before and after a request is handled -> Option AQuick Check:
Interceptor purpose = run code before/after request [OK]
- Confusing interceptors with middleware
- Thinking interceptors handle routing
- Assuming interceptors manage authentication
Solution
Step 1: Recall the interceptor interface
The NestJS interceptor interface requires implementing the intercept() method.Step 2: Verify other options
Methods like handle(), execute(), or process() are not part of the interceptor interface.Final Answer:
intercept() -> Option BQuick Check:
Interceptor method = intercept() [OK]
- Using handle() instead of intercept()
- Confusing with middleware method names
- Forgetting to implement intercept()
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before handler');
return next.handle().pipe(
tap(() => console.log('After handler'))
);
}
}Solution
Step 1: Analyze the intercept method
The interceptor logs 'Before handler' immediately, then calls next.handle() which returns an Observable.Step 2: Understand the tap operator
The tap operator logs 'After handler' when the Observable emits after the request handler finishes.Final Answer:
'Before handler' then 'After handler' are logged -> Option CQuick Check:
Logs before and after handler = 'Before handler' then 'After handler' are logged [OK]
- Thinking only one log appears
- Ignoring the Observable pipe behavior
- Assuming synchronous logging only
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class ErrorInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
try {
return next.handle();
} catch (error) {
console.error('Error caught:', error);
throw error;
}
}
}Solution
Step 1: Understand async error handling in interceptors
next.handle() returns an Observable, so errors happen asynchronously and are not caught by try-catch.Step 2: Identify the problem with the try-catch
The try-catch only catches synchronous errors, so async errors must be handled with RxJS operators like catchError.Final Answer:
The try-catch block won't catch async errors from next.handle() -> Option DQuick Check:
Async errors need RxJS catchError, not try-catch [OK]
- Using try-catch for async Observable errors
- Assuming intercept returns void
- Not handling errors inside pipe
response.duration. Which approach correctly implements this?Solution
Step 1: Understand timing with interceptors
Start time must be recorded before calling next.handle(), which returns an Observable.Step 2: Use tap() to run code after handler finishes
tap() lets you calculate duration after the response is ready and modify it safely.Step 3: Evaluate options
Record start time, call next.handle(), then use tap() to calculate duration and modify response before returning correctly uses tap() after next.handle() to set response.duration. Record start time, use try-catch around next.handle(), then set duration after catch uses try-catch incorrectly for async. Modify response before calling next.handle(), then record duration after modifies response too early. Use a middleware instead of interceptor to measure time suggests middleware, which is not the question focus.Final Answer:
Record start time, call next.handle(), then use tap() to calculate duration and modify response before returning -> Option AQuick Check:
Use tap() after next.handle() to measure time [OK]
- Trying to catch async errors with try-catch
- Modifying response before handler runs
- Confusing middleware with interceptor roles
Ready to prove it?
Pass the test and this pattern moves unknown
