1. 서론
Interceptor
는 요청 또는 응답이 라우트 핸들러 또는 컨트롤러에 의해 처리되기 전에 로깅이나 요청 또는 응답 수정과 같은 특정 작업을 수행할 수 있게 해준다.
인증, 인가, 오류 처리와 같은 특정 라우트나 컨트롤러와 관계없는 일련의 절차를 구현할 수 있다.
Nest.js에서 Interceptor를 만들려면 NestInterceptor
인터페이스를 implements하고 intercept
메서드를 정의해야 한다.
이 메서드는 ExecutionContext
와 CallHandler
를 인수로 받고 응답을 나타내는 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)
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...');
}),
);
}
}
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)
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 };
}),
);
}
}
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 라이프 사이클
Incoming request
Globally bound middleware
Module bound middleware
Global guards
Controller guards
Route guards
Global interceptors (pre-controller)
Controller interceptors (pre-controller)
Route interceptors (pre-controller)
Global pipes
Controller pipes
Route pipes
Route parameter pipes
Controller (method handler)
Service (if exists)
Route interceptor (post-request)
Controller interceptor (post-request)
Global interceptor (post-request)
Exception filters (route, then controller, then global)
Server response