Bird
Raised Fist0
NestJSframework~10 mins

Interceptor interface in NestJS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Interceptor interface
Request received
↓
Interceptor intercept() called
↓
Execute pre-processing logic
↓
Call next.handle() to continue
↓
Wait for response Observable
↓
Execute post-processing logic on response
↓
Return modified or original response
↓
Response sent to client
The interceptor intercepts the request, runs code before and after the main handler, then returns the response.
Execution Sample
NestJS
intercept(context, next) {
  console.log('Before handler');
  return next.handle().pipe(
    tap(() => console.log('After handler'))
  );
}
Logs a message before and after the main request handler runs.
Execution Table
StepActionEvaluationResult
1Interceptor intercept() calledcontext and next receivedReady to process request
2Log 'Before handler'Console logs messageMessage shown before handler
3Call next.handle()Returns Observable of handler responseWaiting for response
4Response emittedtap operator triggersLog 'After handler'
5Return responseResponse sent to clientRequest completed
💡 Response sent to client, interceptor completes execution
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
contextProvided by NestJSSameSameSameSame
nextProvided by NestJSSameSameSameSame
Observable responseNot startedNot startedWaitingEmittedCompleted
Key Moments - 2 Insights
Why do we call next.handle() inside intercept()?
Calling next.handle() continues the request to the next handler or interceptor. Without it, the request would stop here. See execution_table step 3.
How can we run code after the main handler finishes?
We use operators like tap() on the Observable returned by next.handle() to run code after the response emits. See execution_table step 4.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what happens at step 2?
AThe main handler is called
BThe response is sent to the client
CThe interceptor logs a message before the handler runs
DThe interceptor finishes execution
💡 Hint
Check the 'Action' and 'Result' columns at step 2 in the execution_table
At which step does the interceptor wait for the handler's response?
AStep 3
BStep 1
CStep 4
DStep 5
💡 Hint
Look for when next.handle() is called and the Observable is waiting
If we remove next.handle() call, what will happen?
AThe interceptor will log messages twice
BThe request will stop and client gets no response
CThe request will continue normally
DThe response will be sent immediately
💡 Hint
Refer to key_moments about why next.handle() is necessary
Concept Snapshot
Interceptor interface in NestJS:
- intercept(context, next) method runs on each request
- Call next.handle() to continue request pipeline
- Use RxJS operators (e.g., tap) to run code after handler
- Can modify request or response
- Useful for logging, caching, transforming responses
Full Transcript
In NestJS, an Interceptor implements the intercept() method. When a request comes in, intercept() runs first. It can run code before the main handler by placing logic before calling next.handle(). Calling next.handle() continues the request to the next handler or interceptor and returns an Observable of the response. We can use RxJS operators like tap() on this Observable to run code after the handler finishes, such as logging or modifying the response. Finally, the response is sent back to the client. If next.handle() is not called, the request stops and the client does not get a response. This flow allows interceptors to add behavior around request handling, like logging or caching.

Practice

(1/5)
1. What is the primary purpose of an interceptor in NestJS?
easy
A. To run code before and after a request is handled
B. To define database schemas
C. To handle HTTP routing
D. To manage user authentication

Solution

  1. Step 1: Understand the role of interceptors

    Interceptors in NestJS are designed to execute code before and after the main request handler runs.
  2. Step 2: Compare with other options

    Database schemas, routing, and authentication are handled by other parts of NestJS, not interceptors.
  3. Final Answer:

    To run code before and after a request is handled -> Option A
  4. Quick Check:

    Interceptor purpose = run code before/after request [OK]
Hint: Interceptors wrap request handling with extra code [OK]
Common Mistakes:
  • Confusing interceptors with middleware
  • Thinking interceptors handle routing
  • Assuming interceptors manage authentication
2. Which method must be implemented when creating a NestJS interceptor?
easy
A. handle()
B. intercept()
C. execute()
D. process()

Solution

  1. Step 1: Recall the interceptor interface

    The NestJS interceptor interface requires implementing the intercept() method.
  2. Step 2: Verify other options

    Methods like handle(), execute(), or process() are not part of the interceptor interface.
  3. Final Answer:

    intercept() -> Option B
  4. Quick Check:

    Interceptor method = intercept() [OK]
Hint: Remember: intercept() runs your interceptor logic [OK]
Common Mistakes:
  • Using handle() instead of intercept()
  • Confusing with middleware method names
  • Forgetting to implement intercept()
3. Given this interceptor code snippet, what will be logged?
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'))
    );
  }
}
medium
A. Only 'Before handler' is logged
B. Only 'After handler' is logged
C. 'Before handler' then 'After handler' are logged
D. No logs are produced

Solution

  1. Step 1: Analyze the intercept method

    The interceptor logs 'Before handler' immediately, then calls next.handle() which returns an Observable.
  2. Step 2: Understand the tap operator

    The tap operator logs 'After handler' when the Observable emits after the request handler finishes.
  3. Final Answer:

    'Before handler' then 'After handler' are logged -> Option C
  4. Quick Check:

    Logs before and after handler = 'Before handler' then 'After handler' are logged [OK]
Hint: tap() logs after the handler completes [OK]
Common Mistakes:
  • Thinking only one log appears
  • Ignoring the Observable pipe behavior
  • Assuming synchronous logging only
4. What is wrong with this interceptor implementation?
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;
    }
  }
}
medium
A. The interceptor should not throw errors
B. The intercept method must return void, not Observable
C. Missing call to next.handle() inside try block
D. The try-catch block won't catch async errors from next.handle()

Solution

  1. Step 1: Understand async error handling in interceptors

    next.handle() returns an Observable, so errors happen asynchronously and are not caught by try-catch.
  2. 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.
  3. Final Answer:

    The try-catch block won't catch async errors from next.handle() -> Option D
  4. Quick Check:

    Async errors need RxJS catchError, not try-catch [OK]
Hint: Use RxJS catchError for async errors, not try-catch [OK]
Common Mistakes:
  • Using try-catch for async Observable errors
  • Assuming intercept returns void
  • Not handling errors inside pipe
5. You want to create an interceptor that measures how long a request takes and adds this duration to the response object as response.duration. Which approach correctly implements this?
hard
A. Record start time, call next.handle(), then use tap() to calculate duration and modify response before returning
B. Record start time, use try-catch around next.handle(), then set duration after catch
C. Modify response before calling next.handle(), then record duration after
D. Use a middleware instead of interceptor to measure time

Solution

  1. Step 1: Understand timing with interceptors

    Start time must be recorded before calling next.handle(), which returns an Observable.
  2. Step 2: Use tap() to run code after handler finishes

    tap() lets you calculate duration after the response is ready and modify it safely.
  3. 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.
  4. Final Answer:

    Record start time, call next.handle(), then use tap() to calculate duration and modify response before returning -> Option A
  5. Quick Check:

    Use tap() after next.handle() to measure time [OK]
Hint: Use tap() after next.handle() to add timing info [OK]
Common Mistakes:
  • Trying to catch async errors with try-catch
  • Modifying response before handler runs
  • Confusing middleware with interceptor roles
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard