2022. 12. 14. 19:12ㆍBackend Development/NestJS
NestJS는 강력한 모듈화와 데코레이터 기반 구조를 통해 애플리케이션의 다양한 측면을 쉽게 관리할 수 있는 프레임워크입니다. 이 중 인터셉터는 요청과 응답을 가로채어 추가 로직을 실행할 수 있는 중요한 기능입니다. 이 글에서는 인터셉터를 사용하여 로깅 처리를 구현하는 방법을 다룹니다.
1. NestJS의 인터셉터란?
NestJS의 인터셉터는 요청과 응답의 흐름을 제어하거나 데이터를 변환할 때 사용됩니다. 다음과 같은 기능을 수행할 수 있습니다:
- 요청 및 응답 가로채기
요청이 컨트롤러에 도달하기 전, 응답이 클라이언트로 전달되기 전에 추가 작업을 수행합니다. - 응답 데이터 변환
컨트롤러에서 반환된 데이터를 원하는 형태로 변환할 수 있습니다. - 예외 처리
실행 중 발생한 예외를 포착하여 변환하거나 추가적인 처리를 수행할 수 있습니다.
인터셉터의 구조
NestJS의 인터셉터는 NestInterceptor
인터페이스를 구현하여 생성됩니다.
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class ExampleInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// 요청 전 로직
console.log('Before...');
return next
.handle() // 다음 미들웨어 또는 컨트롤러 호출
.pipe(
// 응답 후 로직
);
}
}
2. 로깅 인터셉터 구현하기
로깅 인터셉터를 만들어 요청 처리 시간을 측정하고 로그를 기록하는 방법을 살펴보겠습니다.
로깅 인터셉터 코드
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> {
const now = Date.now();
console.log('Request started...');
return next
.handle()
.pipe(
tap(() =>
console.log(`Request completed in ${Date.now() - now}ms`),
),
);
}
}
코드 설명
ExecutionContext
: 요청에 대한 정보를 가져올 수 있습니다. 예: 요청의 경로, 메서드, 헤더 등.CallHandler
: 컨트롤러의 요청 처리를 담당합니다.tap
연산자: RxJS의 연산자로, 응답이 처리된 후 추가 로직을 실행할 수 있습니다.
3. 인터셉터 적용하기
3.1. 특정 라우트에 적용
인터셉터를 특정 라우트에서만 사용하려면, 메서드 수준에서 @UseInterceptors()
데코레이터를 사용합니다.
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';
@Controller('example')
export class ExampleController {
@Get()
@UseInterceptors(LoggingInterceptor)
getExample() {
return { message: 'Hello World!' };
}
}
3.2. 컨트롤러 전체에 적용
컨트롤러 수준에서 인터셉터를 적용하려면, @UseInterceptors()
데코레이터를 클래스 위에 추가합니다.
@UseInterceptors(LoggingInterceptor)
@Controller('example')
export class ExampleController {
@Get()
getExample() {
return { message: 'Hello World!' };
}
}
3.3. 글로벌 적용
애플리케이션 전체에서 인터셉터를 사용하려면, app.useGlobalInterceptors()
를 사용합니다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { LoggingInterceptor } from './logging.interceptor';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());
await app.listen(3000);
}
bootstrap();
4. 고급 활용: 응답 데이터 변환
인터셉터는 로깅 외에도 응답 데이터를 변환하거나 특정 형식으로 가공하는 데 유용합니다.
응답 데이터 변환 예제
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map((data) => ({
success: true,
data,
})),
);
}
}
결과
컨트롤러에서 반환한 데이터를 아래와 같이 변환합니다:
{
"success": true,
"data": {
"message": "Hello World!"
}
}
5. 모범 사례
- 단일 책임 원칙 적용
각 인터셉터는 단일 목적을 가져야 합니다. 로깅, 데이터 변환 등 각 작업을 분리하여 관리하세요. - 재사용 가능한 인터셉터 작성
공통 로직은 재사용 가능하도록 모듈화하고 글로벌 적용을 고려하세요. - 에러 핸들링
실행 중 발생할 수 있는 예외를 인터셉터에서 처리하여 일관된 에러 응답을 제공합니다.
6. 마무리
NestJS의 인터셉터는 요청 및 응답 흐름을 제어하고, 공통 작업을 효율적으로 관리할 수 있는 강력한 도구입니다. 이 글에서는 로깅을 중심으로 인터셉터의 기본 사용법과 고급 활용 방법을 살펴보았습니다. 인터셉터를 적절히 활용하면 애플리케이션의 유지보수성과 확장성을 크게 향상시킬 수 있습니다.
궁금한 점이 있다면 댓글로 남겨주세요! 😊
'Backend Development > NestJS' 카테고리의 다른 글
NestJS 에서 class-validator 를 활용한 데이터 검증 방법 (0) | 2023.06.26 |
---|---|
NestJS 로 간단한 회원가입 기능 구현하기 (0) | 2023.06.25 |
NestJS에서 @typescript-eslint/no-unused-vars 오류 해결 방법 (0) | 2022.12.15 |
NestJS 프로젝트에 TypeORM 설정 및 적용 가이드 (0) | 2022.11.20 |