-
Nest.js Interceptors 사용하기FrameWork/Nest.js 2022. 8. 7. 16:09
Interceptor의 역할
Nest.js에서 AOP 패턴의 특징을 차용한 것으로
예)
// A -> B -> C -> D // A -> C -> D // A -> E -> F -> D -> G // Z -> A -> X -> D
언 뜻 보면 각 4개의 router에 공통점이 없는 듯이 보이지만, 잘 찾아보면 A가 먼저 실행되고, 끝 부분에는 D가 실행된다는 공통점이 있다.
다시 말해 4개의 router 모두다 middleware A와 D는 공통적으로 거쳐간다는 것 을 알 수 있다.
이런 A와 D와 같은 middleware들을 한번 정의해서 필요 할때마다 쓸 수 있도록 재 사용성을 갖도록 하는 것이 Intercepter의 존재의 이유이자 역할이다.
Interceptor의 실행 순서
middleware
1. Globally bound middleware
2. Module bound middleware
guard
4. Global guard
5. Controller guard
6. Route guard
(pre)Intercceptor
7. Global intercceptors (pre-controller)
8. Controller intercceptors (pre-controller)
9. Route intercceptors (pre-controller)
pipes
10. Global pipes
11. Controller pipes
12. Route pipes
13.Route parameter pipes
14.Controller (method handler)
15.Service(존재한다면)
(post)interccepter
16. Route intercceptors (post-request)
17. Controller intercceptors (post-request)
18. Global intercceptors (post-request)
exception
19 Exception filters (route > controller > global)
20.서버에서 응답그래서 intercepter는 main Controller가 있으면, Controller 실행 전이랑 Controller 실행 후에 총 2번 넣어 줄 수 있다.
Middleware와 비교한 Interceptor의 이점
https://dodote10.tistory.com/235
지난번에 만든 LoggerMiddleware 같은 경우 같은 기능을 Interceptror로 구현해도 된다.
LoggerMiddleware 와 같은 경우는 controller가 실행되기 전에 시작해서, next()로 다음 Middleware를 실행 시켰다가 controller가 끝나면 response 객체로 logging을 해준다.
보통 express의 middleware라고 생각을 하면, 마지막에 res.json() 혹은 res.send() 보내기 전에 만 여러 동작을 많이 추가해주었다. 전에만 동작 추가를 많이 해주고, res.json()을 보낸 다음에는 응답이 보내졌다고 생각하고 끝이였다.
하지만, response를 보냈어도 그전에 한번더 조작을 해주면 좋다고 생각할 경우에 유용하다. 즉 controller에서 보낸 data를 한번더 가공할 수 있는 틈이 생긴다.
Interceptor 만들기
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class UndefinedToNullInterceptor implements NestInterceptor { intercept( context: ExecutionContext, next: CallHandler<any>, ): Observable<any> | Promise<Observable<any>> { // (controller)전 부분 return next.handle().pipe()~~~ } }
controller 실행 되고, 난 후에는 handle() 메서드 다음에 작성하면 된다.
Interceptor을 이용해서 반환 값 가공하기
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { map, Observable } from 'rxjs'; @Injectable() export class UndefinedToNullInterceptor implements NestInterceptor { intercept( context: ExecutionContext, next: CallHandler<any>, ): Observable<any> | Promise<Observable<any>> { return next.handle().pipe(map((data) => ({ data, code: 'SUCCESS' }))); } }
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { map, Observable } from 'rxjs'; @Injectable() export class UndefinedToNullInterceptor implements NestInterceptor { intercept( context: ExecutionContext, next: CallHandler<any>, ): Observable<any> | Promise<Observable<any>> { return next .handle() .pipe(map((data) => (data === undefinded ? null : data))); } }
공식문서에는 보통 handle()메서드 이후에는 rx가 많이 등장한다. 공식문서에서는 return 전에 rx에서 map()이라는 메서드를 가져와서 위와 같은 코드로 Interceptor를 정의한다.
map메서드 안에 arrow function에 인자로 들어간 data는 controller에서 반환하는 값을 의미 controller에서 반환하는 값을 {data : 반환값} 형태 object안에 담겠다는 의미이다.
json는 null 값만 취급 하고 undefined를 모른다. 그래서 json값에 undefined가 들어가면 error가 발생 할 수 있다.
Interceptor controller 단위로 적용 시
@UseInterceptors(UndefinedToNullInterceptor) @ApiTags('USER') @Controller('api/users') export class UsersController { ....
router에 만 적용하고 싶다면 해당하는 메서드 위에만 @UseInterceptors()를 사용하여 적용시켜 주어도 된다.
'FrameWork > Nest.js' 카테고리의 다른 글
Next.js custom decorator만들기 (0) 2022.08.07 Nest.js 커스텀 Middleware 만들기 (0) 2022.08.04 Multer와 미디어 파일 서비스(img,mp3,mp4) 1 (0) 2022.07.30 Nest.js Intercepters(AOP 패턴) (0) 2022.07.24 Nest.js Pipes(변환, 유효성 검사) (0) 2022.07.11