Interceptor

유석현(SeokHyun Yu)·2022년 12월 25일
0

Nest.js

목록 보기
9/9
post-thumbnail
post-custom-banner

1. 서론

Interceptor는 요청 또는 응답이 라우트 핸들러 또는 컨트롤러에 의해 처리되기 전에 로깅이나 요청 또는 응답 수정과 같은 특정 작업을 수행할 수 있게 해준다.

인증, 인가, 오류 처리와 같은 특정 라우트나 컨트롤러와 관계없는 일련의 절차를 구현할 수 있다.

Nest.js에서 Interceptor를 만들려면 NestInterceptor 인터페이스를 implements하고 intercept 메서드를 정의해야 한다.

이 메서드는 ExecutionContextCallHandler를 인수로 받고 응답을 나타내는 Observable을 반환한다.

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

@Injectable()
export class SuccessInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle();
  }
}

2. 사용 방법 (tap)

success.interceptor.ts

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

@Injectable()
export class SuccessInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Before...');

    return next.handle().pipe(
      tap(() => {
        console.log('After...');
      }),
    );
  }
}

app.controller.ts

import { SuccessInterceptor } from './success/success.interceptor';
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
@UseInterceptors(SuccessInterceptor)
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello() {
    console.log('hello');

    return null;
  }
}

tap()은 RxJS 함수로서, 로깅이나 디버깅과 같은 사이드 이펙트를 수행한다.

위 사진을 보면 interceptor의 return 이전 로직들은 Controller 이전에 수행되고, 그 다음은 Controller, 마지막으로 Interceptor에서 return 되는 tap 연산자 안의 로직이 수행되는 것을 볼 수 있다.


3. 사용 방법 (map)

success.interceptor.ts

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

@Injectable()
export class SuccessInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map((data) => {
        return { success: true, data };
      }),
    );
  }
}

app.controller.ts

import { SuccessInterceptor } from './success/success.interceptor';
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
@UseInterceptors(SuccessInterceptor)
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello() {
    return { name: 'SeokHyun Yu', age: 25 };
  }
}

map() 역시 RxJS 함수이지만, tap과는 달리 Controlller에서 return 된 값을 받아서 새로운 값을 생성한 다음 그 결과 값을 전달한다.

위 사진을 살펴보면 분명 Controller에서 { name: 'SeokHyun Yu', age: 25 }를 반환했는데 response는 interceptor에서 변환해준 값으로 반환된 것을 볼 수 있다.


4. Request 라이프 사이클

  1. Incoming request

  2. Globally bound middleware

  3. Module bound middleware

  4. Global guards

  5. Controller guards

  6. Route guards

  7. Global interceptors (pre-controller)

  8. Controller interceptors (pre-controller)

  9. Route interceptors (pre-controller)

  10. Global pipes

  11. Controller pipes

  12. Route pipes

  13. Route parameter pipes

  14. Controller (method handler)

  15. Service (if exists)

  16. Route interceptor (post-request)

  17. Controller interceptor (post-request)

  18. Global interceptor (post-request)

  19. Exception filters (route, then controller, then global)

  20. Server response

profile
Backend Engineer
post-custom-banner

0개의 댓글