Bird
Raised Fist0
NestJSframework~10 mins

Exception mapping interceptor in NestJS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Exception mapping interceptor
Request received
↓
Interceptor intercepts
↓
Try to handle request
↓
Exception thrown?
No→Return response
Yes↓
Catch exception
↓
Map exception to response
↓
Return mapped response
The interceptor catches exceptions during request handling, maps them to custom responses, and returns them instead of raw errors.
Execution Sample
NestJS
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

@Injectable()
export class ExceptionMappingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    return next.handle().pipe(
      catchError(err => {
        const mappedError = mapException(err);
        return throwError(() => mappedError);
      }),
    );
  }
}

function mapException(err) {
  if (err.status === 404) {
    return new Error('Resource not found');
  }
  return err;
}
This interceptor catches errors from request handlers, maps 404 errors to a custom message, and rethrows them.
Execution Table
StepActionException Thrown?Exception Caught?Exception Mapped?Response Returned
1Request received and passed to interceptorNoNoNoNo
2Handler executes normallyNoNoNoResponse from handler
3Request received and passed to interceptorYes (404 error)NoNoNo
4Interceptor catches exceptionYesYesNoNo
5Interceptor maps exception to custom errorYesYesYesNo
6Interceptor returns mapped error as responseYesYesYesMapped error response
💡 Execution stops after interceptor returns either normal or mapped error response.
Variable Tracker
VariableStartAfter Step 3After Step 5Final
errundefinedError with status 404Mapped Error('Resource not found')Mapped Error('Resource not found')
mappedErrorundefinedundefinedMapped Error('Resource not found')Mapped Error('Resource not found')
Key Moments - 2 Insights
Why does the interceptor catch the exception instead of letting it crash the app?
Because in step 4 the interceptor uses catchError to catch exceptions from the handler, preventing app crash and allowing custom handling.
What happens if the exception is not a 404 error?
At step 5, mapException returns the original error unchanged, so the interceptor rethrows the original error.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is returned at step 2?
AException thrown
BMapped error response
CResponse from handler
DNo response
💡 Hint
Check the 'Response Returned' column at step 2 in the execution_table.
At which step does the interceptor map the exception to a custom error?
AStep 3
BStep 5
CStep 4
DStep 6
💡 Hint
Look at the 'Exception Mapped?' column in the execution_table.
If the error status was 500 instead of 404, what would happen at step 5?
AException would be unchanged
BException would be mapped to 'Resource not found'
CInterceptor would ignore the error
DResponse would be successful
💡 Hint
Refer to the mapException function logic in the execution_sample.
Concept Snapshot
Exception Mapping Interceptor in NestJS:
- Intercepts requests and catches exceptions from handlers.
- Uses RxJS catchError to handle errors.
- Maps specific exceptions (e.g., 404) to custom errors.
- Returns mapped errors as responses instead of raw exceptions.
- Helps customize error responses and improve app stability.
Full Transcript
In NestJS, an Exception Mapping Interceptor catches errors thrown by request handlers. When a request comes in, the interceptor lets the handler run. If the handler throws an error, the interceptor catches it using RxJS catchError. It then checks the error type and maps it to a custom error if needed, for example changing a 404 error to a 'Resource not found' message. Finally, it returns this mapped error as the response. This prevents raw errors from crashing the app and allows sending friendly error messages to clients.

Practice

(1/5)
1. What is the main purpose of an ExceptionMappingInterceptor in NestJS?
easy
A. To catch exceptions and transform them into user-friendly responses
B. To log all incoming HTTP requests
C. To validate incoming request data automatically
D. To manage database connections

Solution

  1. Step 1: Understand the role of interceptors

    Interceptors in NestJS can modify requests or responses and handle errors.
  2. Step 2: Identify the function of exception mapping

    An ExceptionMappingInterceptor specifically catches exceptions and converts them into consistent, user-friendly API responses.
  3. Final Answer:

    To catch exceptions and transform them into user-friendly responses -> Option A
  4. Quick Check:

    Exception mapping = user-friendly error response [OK]
Hint: Exception interceptors catch errors and format responses [OK]
Common Mistakes:
  • Confusing interceptors with middleware for logging
  • Thinking interceptors validate data automatically
  • Assuming interceptors manage database connections
2. Which RxJS operator is commonly used inside an ExceptionMappingInterceptor to handle errors?
easy
A. map
B. filter
C. tap
D. catchError

Solution

  1. Step 1: Recall RxJS operators for error handling

    The catchError operator is designed to catch errors in an observable stream.
  2. Step 2: Match operator to interceptor usage

    ExceptionMappingInterceptor uses catchError to catch exceptions and transform them.
  3. Final Answer:

    catchError -> Option D
  4. Quick Check:

    RxJS error handling = catchError [OK]
Hint: Use catchError to catch and transform errors in observables [OK]
Common Mistakes:
  • Using map which transforms data but doesn't catch errors
  • Confusing filter with error handling
  • Using tap which is for side effects, not error catching
3. Given this ExceptionMappingInterceptor code snippet, what will be the output if the handler throws an error?
intercept(context, next) {
  return next.handle().pipe(
    catchError(err => {
      return throwError(() => new BadRequestException('Mapped error'));
    }),
  );
}
medium
A. The original error is sent to the client
B. No error is sent; the request succeeds silently
C. A BadRequestException with message 'Mapped error' is sent to the client
D. A syntax error occurs and the app crashes

Solution

  1. Step 1: Analyze the catchError block

    When an error occurs, catchError catches it and returns a new BadRequestException with a custom message.
  2. Step 2: Understand the effect on the client response

    The client receives the new BadRequestException with message 'Mapped error' instead of the original error.
  3. Final Answer:

    A BadRequestException with message 'Mapped error' is sent to the client -> Option C
  4. Quick Check:

    Error replaced by BadRequestException [OK]
Hint: catchError replaces original error with mapped exception [OK]
Common Mistakes:
  • Thinking original error passes through unchanged
  • Assuming no error is sent and request succeeds
  • Confusing syntax error with runtime error
4. Identify the error in this ExceptionMappingInterceptor code:
intercept(context, next) {
  return next.handle().pipe(
    catchError(err => {
      throw new HttpException('Error occurred', 400);
    }),
  );
}
medium
A. No error; code is correct
B. Using throw inside catchError instead of returning an observable error
C. Incorrect status code 400 instead of 500
D. Missing import for HttpException

Solution

  1. Step 1: Understand catchError usage

    Inside catchError, you must return an observable error, not throw an error directly.
  2. Step 2: Identify correct error handling

    The code should return throwError(() => new HttpException(...)) instead of throwing.
  3. Final Answer:

    Using throw inside catchError instead of returning an observable error -> Option B
  4. Quick Check:

    catchError must return observable error, not throw [OK]
Hint: Return throwError inside catchError, don't throw directly [OK]
Common Mistakes:
  • Throwing error directly inside catchError
  • Ignoring observable error return requirement
  • Assuming status code 400 is wrong here
5. You want to create an ExceptionMappingInterceptor that converts all QueryFailedError exceptions into BadRequestException with a custom message, but lets other exceptions pass unchanged. Which code snippet correctly implements this behavior?
hard
A. return next.handle().pipe(catchError(err => { if (err instanceof QueryFailedError) { return throwError(() => new BadRequestException('Invalid query')); } return throwError(() => err); }));
B. return next.handle().pipe(catchError(err => { if (err instanceof QueryFailedError) { throw new BadRequestException('Invalid query'); } throw err; }));
C. return next.handle().pipe(catchError(err => { if (err.name === 'QueryFailedError') { return new BadRequestException('Invalid query'); } return err; }));
D. return next.handle().pipe(catchError(err => { if (err instanceof BadRequestException) { return throwError(() => new QueryFailedError()); } return throwError(() => err); }));

Solution

  1. Step 1: Check error type and return observable error

    The interceptor must check if the error is a QueryFailedError instance and return a new BadRequestException wrapped in throwError.
  2. Step 2: Pass other errors unchanged as observable errors

    Other errors must be re-thrown as observable errors using throwError to keep the stream consistent.
  3. Final Answer:

    Option A correctly checks error type and returns observable errors properly -> Option A
  4. Quick Check:

    Use instanceof + throwError for error mapping [OK]
Hint: Use instanceof and return throwError for mapped and original errors [OK]
Common Mistakes:
  • Throwing errors directly inside catchError
  • Returning error objects instead of observable errors
  • Checking error name string instead of instanceof
  • Swapping error types incorrectly
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