NestJS-Interceptor

효딩딩·2023년 7월 19일
0

Interceptor

  • 인터셉터는 @Injectable() 데코레이터 사용하여 의존성 주입(DI)이 가능하다.
  • NestInterceptor 인터페이스로 구현해야한다.
  • controller 가 데이터를 보냈을 때 그것을 받아 가공해서 필터처럼 사용가능하다.
  • 미들웨어와 다른점은 Request lifecycle에 실행 순서가 다르다.
  • 인터셉터가 AOP(Aspect Oriented Programming) 영감을 받았다.

AOP(Aspect Oriented Programming) : 관점 지향 프로그램

  • 목적 : 모듈성을 높이는 것을 목표로 하는 프로그래밍 패러다임이다.

    그림설명
    핵심기능 3가지가 있고 핵심 기능이 각각의 컨트롤러라고 생각해보자.
    각각의 컨트롤러는 저마다 수행하는 기능이 있지만 공통적으로 수행하는 기능도 존재한다.
    예를 들어 클라이언트가 서버에게 어떤 요청을 보냈는지에 대한 정보를 출력하는 Logging기능이 각 컨트롤러에 공통적으로 존재controller 가 시작하기 전과 끝났을 때 나눠서 코딩을 할 수 있는것이다.

실패했을 때 에러를 exception filter 로 만들고

이제는 성공했을 때 공통적인 성공 문구를 interceptor로 구현해보자!

전체모듈에서 공통적으로 사용 가능하기 때문에
commom > interceptors > successInterceptor.ts 폴더 정리하기.
nestJS-공식문서내용 붙여넣기

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

@Injectable()
export class SuccessInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// (1)
   console.log('Before...'); 
   const now = Date.now();
   return next.handle()
     .pipe(
    tap(() => console.log(`After... ${Date.now() -now}ms`)),
     );
    
   // (2) Exception filter 처럼 성공시 데이터가 success: true가 포함되게하자.
     return next.handle()
       .pipe(map((data) => ({ success: true, data,})),); 
  }
}   
- rxjs 형식에서 return next.handle().pipe(map((data) => ())
map을 통해 data를 인자로 받고 응답을 해주는 로직이다.map은 rxjs에서 나온것인데 nest와 별개 라이브러리이고 
nest에서 사용할 때는 형식이 정해져 있다. data는 response의 인자를 받는것이다.
controller가 먼저 실행 되기때문에 controller에서 return 한 값을 받는것이다.

사용하기 위해 의존성 주입하기 catsController.ts

@Controller('cat')
@UseInterceptors(SuccessInterceptor) // 사용 할곳에 인폴트하기 
@UseFilters(HttpExceptionFilter) // exception filter와 비슷하게 사용한다.
export class UserController {

사용할 곳에 console.log를 찍어보자! catsService.ts

// (1)
//    @Get()
//    getAllCat() {
//    console.log('hi controller')  
//    return 'get all cats'
//      }
// (2)
   @Get()
    getAllCat() {
    console.log('hi controller')  
      // 실제 restAPI 처럼 키벨류 형식으로 작성하기.
    return {'cat': 'get all cats'} 
      }

---------------------------------
- postman 에 GET http://localhost:3000/cats 보내기

// (1)
   get all cats (postman 응답 시)
console.log 찍힌것 
// Before... 
// hi controller
// After
- 해당 클래스에  @UseInterceptors(SuccessInterceptor) 를 의존성 주입을 했다.
@Get() 해당 함수에 요청을 보내면 console.log('hi controller') 이 찍힌다.
인터셉터를 보면 Before...는 와 After...가 있는데 
Before는 pre-controller 로 controller 시작전에 실행하는것이고 
After는 post-request 로 controller 후에 실행하는 인터셉터이다. 
이렇게 공통된것을 AOP(Aspect Oriented Programming) 시각으로 모듈화를 시킨것이다. 


// (2)
{
 "success": true,
 "dat": { "cat": "get all cats"}    
}
- 이렇게 하면 데이터 형식을 유지하면서 프론트한테 보내줄 수 있다. 
프론트에서는 success를 기준으로 성공,실패 어떤 응답인지 구분하기 쉬워진다.

Request lifecycle

NestJS-수명주기

  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

순서
사용자의 request를 받고
middleware를 거쳐
guards 거쳐
interceptors(pre-controller)를 거쳐
pipes 거친 파라미터 결과값이
controller에서 사용되고
service에서 데이터가 사용이되고
interceptor (post-request) 거친다.
여기서 쭉 오다가 exception이 발생되면 Exception filters 로 나가게 된다.
그리고 사용자에게 response를 넘겨주게 된다.

  • 인터셉터는 pre-controller 와 post-request 두가지가 있다.
    interceptor(pre-controller)가 controller 시작 전에 실행이 되는것이고 interceptor(post-request)는 controller 와 service를 거친 후 실행된다.
profile
어제보다 나은 나의 코딩지식

1개의 댓글

comment-user-thumbnail
2023년 7월 19일

유익한 정보를 제공해주셔서 감사합니다.

답글 달기