0
0
NestjsHow-ToBeginner ยท 4 min read

How to Create an Interceptor in NestJS: Simple Guide

In NestJS, create an interceptor by implementing the NestInterceptor interface and overriding the intercept method. Then, apply it globally or to specific routes using decorators like @UseInterceptors().
๐Ÿ“

Syntax

An interceptor in NestJS is a class that implements the NestInterceptor interface. It must have an intercept(context, next) method that handles the request and response flow.

  • context: Provides details about the current request.
  • next: A handler to continue the request pipeline.

Return an observable from intercept to manipulate the response.

typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class ExampleInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // Code before request handling
    return next.handle().pipe(
      map(data => {
        // Code after request handling
        return data;
      }),
    );
  }
}
๐Ÿ’ป

Example

This example shows a simple interceptor that logs the time taken by a request and modifies the response by adding a timestamp field.

typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap, map } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    console.log('Before handling request');

    return next.handle().pipe(
      tap(() => console.log(`After... ${Date.now() - now}ms`)),
      map(data => ({ ...data, timestamp: new Date().toISOString() })),
    );
  }
}

// Usage in a controller
import { Controller, Get, UseInterceptors } from '@nestjs/common';

@Controller('test')
@UseInterceptors(LoggingInterceptor)
export class TestController {
  @Get()
  getData() {
    return { message: 'Hello from NestJS' };
  }
}
Output
{"message":"Hello from NestJS","timestamp":"2024-06-01T12:00:00.000Z"} Console logs: Before handling request After... 5ms
โš ๏ธ

Common Pitfalls

  • Forgetting to add @Injectable() decorator to the interceptor class causes NestJS to not recognize it.
  • Not returning next.handle() observable breaks the request flow.
  • Trying to use interceptors without importing or applying them via @UseInterceptors() or globally.
  • Modifying the response incorrectly by not returning the transformed data inside map.
typescript
/* Wrong: Missing @Injectable() and not returning next.handle() */
export class BadInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Intercepted');
    // Missing return next.handle() breaks flow
  }
}

/* Right: Proper usage */
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class GoodInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Intercepted');
    return next.handle();
  }
}
๐Ÿ“Š

Quick Reference

  • Implement NestInterceptor interface.
  • Use @Injectable() decorator.
  • Override intercept(context, next) method.
  • Return next.handle() observable, optionally transformed.
  • Apply interceptor with @UseInterceptors() or globally.
โœ…

Key Takeaways

Create interceptors by implementing the NestInterceptor interface and overriding intercept method.
Always decorate interceptors with @Injectable() to register them properly.
Return next.handle() observable to continue request processing.
Use RxJS operators like map or tap inside intercept to modify or log responses.
Apply interceptors with @UseInterceptors() on controllers or routes, or globally in main.ts.