ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • NestJS 마스터 시리즈 10화. 미들웨어와 인터셉터 – 요청 흐름을 설계하는 법
    기술과 산업/언어 및 프레임워크 2025. 5. 5. 13:38
    728x90

    “NestJS에서 흐름을 다룬다는 건 미들웨어와 인터셉터를 설계한다는 뜻이다”

     

    NestJS의 미들웨어와 인터셉터 개념을 설명하고, 요청 흐름을 설계하는 구조적 방식에 대해 다룹니다. 로깅, 인증, 응답 변환, 실행 시간 측정 등 실무 적용 예제를 포함합니다.

     


     

    요청 흐름을 통제하는 두 가지 축

     

    NestJS의 요청 흐름은 크게 두 축으로 나눌 수 있다.

    계층역할예시

    미들웨어 (Middleware) 요청 전 전처리 인증, 로깅, IP 차단
    인터셉터 (Interceptor) 요청 전/후 중간 개입 응답 포맷 변환, 실행 시간 측정, 캐싱

    이 두 계층을 적절히 활용하면, 컨트롤러 내부의 로직을 건드리지 않고도 서비스 흐름의 품질을 제어할 수 있다.

     


     

    미들웨어 – Express 스타일 요청 전처리

     

    NestJS는 Express 기반이기 때문에 미들웨어의 구조 역시 매우 유사하다.

     

     

    기본 미들웨어 예제

    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';
    
    @Injectable()
    export class LoggerMiddleware implements NestMiddleware {
      use(req: Request, res: Response, next: NextFunction) {
        console.log(`[${req.method}] ${req.originalUrl}`);
        next();
      }
    }

     

    적용 방식

    import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
    import { LoggerMiddleware } from './logger.middleware';
    
    @Module({})
    export class AppModule implements NestModule {
      configure(consumer: MiddlewareConsumer) {
        consumer
          .apply(LoggerMiddleware)
          .forRoutes('*'); // 전체 라우트에 적용
      }
    }

     

    • 특정 경로나 컨트롤러에만 제한적으로 적용할 수도 있다.
    • 주로 로깅, 인증 토큰 전처리, 보안 필터링 용도로 사용된다.

     


     

    인터셉터 – 요청-응답 흐름의 양방향 개입

     

    인터셉터는 @Injectable()로 선언하며, 요청 전, 응답 후 양방향에서 흐름을 가로챌 수 있다.

     

     

    기본 인터셉터 예제

    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();
        return next.handle().pipe(
          tap(() => console.log(`Execution time: ${Date.now() - now}ms`)),
        );
      }
    }

     

    적용 방식

    import { APP_INTERCEPTOR } from '@nestjs/core';
    
    @Module({
      providers: [
        {
          provide: APP_INTERCEPTOR,
          useClass: LoggingInterceptor,
        },
      ],
    })
    export class AppModule {}

     

     


     

    실무 활용 예시

    용도미들웨어인터셉터

    사용자 인증 처리 O X
    요청 로깅 O O (응답 포함 시 인터셉터 사용)
    응답 구조 통일 X O
    실행 시간 측정 X O
    캐싱 처리 X O (CacheInterceptor)
    다국어 응답 변환 X O

     

     


     

    Nest 내장 인터셉터 활용

     

    NestJS는 기본적으로 다음과 같은 유용한 인터셉터를 제공한다:

     

    • ClassSerializerInterceptor : 응답 객체를 DTO에 맞게 직렬화
    • CacheInterceptor : 캐시 자동화
    • TimeoutInterceptor : 응답 타임아웃 제한

     

    이들은 대부분 @UseInterceptors() 데코레이터나 APP_INTERCEPTOR 전역 주입 방식으로 활용된다.

     


     

    사용자 정의 응답 포맷 예제

    return next.handle().pipe(
      map(data => ({
        success: true,
        data,
        timestamp: new Date().toISOString(),
      })),
    );

     

    • 이렇게 응답 포맷을 통일해두면 클라이언트는 항상 동일한 구조를 받을 수 있어 프론트엔드 개발이 편해진다.

     


     

    마무리 인사이트

     

    NestJS에서 흐름을 제어하고 설계하는 방법은 두 가지다:

    미들웨어로 요청 전처리, 인터셉터로 요청-응답 가공.

    이 두 계층을 적절히 분리하면, 비즈니스 로직은 본연에 집중하고, 시스템 전체 흐름은 공통 계층에서 일관되게 관리할 수 있다.

     

    • 인증은 미들웨어에서
    • 응답 포맷과 성능 로깅은 인터셉터에서
    • 흐름의 구조화가 품질을 만든다

     

    “흐름을 설계하지 않으면, 흐름에 끌려간다”

     


     

    다음 회차 예고

     

    NestJS 마스터 시리즈 11화. 파이프(Pipe) – 요청 데이터의 정제와 전처리 전략

    Transform과 ValidationPipe, 커스텀 파이프 설계까지 자세히 분석합니다.

    728x90
Designed by Tistory.