본문 바로가기
개발자 도전기/[STUDY] JS || TS

NestJS | docs | Interceptors & AOP Pattern

by 답수 2023. 2. 24.
728x90
반응형

 

 

 

Interceptors

인터셉터는  @Injectable() 데코레이터를 주석으로 다는 클래스이고,  NestInterceptor 인터페이스를 implements한다.

 

인터셉터는 Aspect Oriented Programming(AOP, 관점 지향 프로그래밍) 기술에서 영감 받은 유용한 기능들을 가지고 있다.

  • bind extra logic before / after method execution
  • transform the result returned from a function
  • transform the exception thrown from a function
  • extend the basic function behavior
  • completely override a function depending on specific conditions (e.g., for caching purposes)

 

▼AOP

더보기

AOP

관점 지향 프로그래밍은 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임을 말한다.

 

AOP가 필요한 상황

  • 모든 메서드의 호출 시간을 측정하고 싶다면?
  • 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)

회원 가입, 회원 조회 기능이 로직을 수행하는데 시간이 얼마나 걸리는지 측정하기 위해서 각 메서드 안에 시간 측정하는 로직을 추가해야 할까? 시간 측정하는 로직이 핵심 관심 사항일까? 즉 시간을 측정하는 로직은 공통 관심 사항이고, 이 기능이 핵심 비즈니스 로직과 섞이게 되면 유지보수가 어렵다.

 

즉 인터셉터는 각각의 핵심 기능을 횡단하면서 재사용성이 가능한 기능들을 관점 지향적으로 하나의 모듈로 묶는 것을 말한다.

 

여태 미들웨어, 파이프, 가드를 배웠고 이제 인터셉터도 배우는데 그럼 요청이 왔을 때 어떤 순서로 진행되는지 점점 혼란스러워진다. NestJS의 Request lifecycle을 보면 다음과 같다.

  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
더 요약하자면 요청이 들어온 이후 미들웨어 → 가드 → 인터셉터(pre-controller) → 파이프 → 컨트롤러 → 서비스 → 인터셉터(post-request) → 응답 / 에러가 발생한다면 예외필터

 

문서에 나온 코드로 예시를 들자면 다음과 같다.

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

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

    const now = Date.now();
    return next
      .handle()
      .pipe(
        tap(() => console.log(`After... ${Date.now() - now}ms`)),  // <-- post-request
      );
  }
}

 

인터셉터는 @UseInterceptors() 데코레이터를 이용하여 컨트롤러에 적용할 수 있다.

 

728x90
반응형

댓글