개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

NestJS Lifecycle — 요청 처리 전체 흐름

2025년 3월 18일
NestJSLifecycleRequest LifecycleMiddlewareGuard

NestJS는 Express 위에서 동작하지만, 요청 하나가 Controller에 도달하기까지 여러 레이어를 순서대로 통과한다. 이 순서를 모르면 Guard에서 막히는 요청이 왜 Middleware 로그에는 찍히는지 이해하기 어렵다. 각 레이어의 역할과 실행 순서를 정확히 짚어 두면 디버깅 시간이 크게 줄어든다.

전체 흐름

HTTP Request
     │
     ▼
┌─────────────┐
│  Middleware  │  Express-level, 순수 함수형
└──────┬──────┘
       │
       ▼
┌─────────────┐
│    Guard    │  인증·인가 — false 반환 시 403
└──────┬──────┘
       │
       ▼
┌───────────────────┐
│ Interceptor (pre) │  실행 전 가로채기
└────────┬──────────┘
         │
         ▼
┌─────────────┐
│    Pipe     │  유효성 검사·변환
└──────┬──────┘
       │
       ▼
┌──────────────┐
│  Controller  │  라우팅·요청 파싱
└──────┬───────┘
       │
       ▼
┌─────────────┐
│   Service   │  비즈니스 로직
└──────┬──────┘
       │
       ▼
┌──────────────┐
│  Repository  │  DB 접근
└──────┬───────┘
       │
       ▼
┌────────────────────┐
│ Interceptor (post) │  응답 변환·로깅
└────────┬───────────┘
         │
         ▼
   HTTP Response

Middleware

Middleware는 NestJS가 아닌 Express 레이어에서 동작한다. app.use로 등록하거나 NestMiddleware를 구현해 모듈에 적용한다. 요청 로깅, CORS, 쿠키 파싱처럼 NestJS의 DI 컨텍스트와 무관한 전처리 작업에 적합하다.

Middleware: 요청이 라우트 핸들러에 도달하기 전에 실행되는 함수. next를 호출해야 다음 단계로 넘어간다.

Guard

Guard는 canActivate 메서드 하나만 구현하면 된다. true를 반환하면 다음 단계로 진행하고, false이면 ForbiddenException이 발생한다. JWT 검증, Role 기반 접근 제어를 여기서 처리한다.

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return validateToken(request.headers.authorization);
  }
}

Interceptor

Interceptor는 RxJS Observable을 반환한다. 요청 전(tap, map)과 응답 후 모두 가로챌 수 있어 응답 래핑, 캐싱, 실행 시간 측정에 사용한다.

Interceptor: AOP(Aspect-Oriented Programming) 패턴을 NestJS에서 구현하는 수단. handle을 호출하는 시점이 Controller 실행 지점이다.

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const start = Date.now();
    return next.handle().pipe(
      tap(() => console.log(`${Date.now() - start}ms`)),
    );
  }
}

Pipe

Pipe는 Controller 메서드 파라미터에 바인딩된다. ParseIntPipe, ValidationPipe 같은 내장 Pipe를 쓰거나 PipeTransform을 직접 구현한다. 유효성 검사 실패 시 BadRequestException을 던진다.

레이어별 예외 처리

각 레이어에서 던진 예외는 Exception Filter가 잡는다. Filter는 Lifecycle 순서에 포함되지 않지만, 어느 레이어에서 예외가 발생했든 마지막에 Filter가 처리해 HTTP 응답으로 직렬화한다.

레이어실패 시 기본 상태코드
Guard403 Forbidden
Pipe400 Bad Request
일반 예외500 Internal Server Error

적용 범위 우선순위

Guard, Interceptor, Pipe는 각각 전역(Global) → 컨트롤러(Controller) → 메서드(Method) 순으로 적용된다. useGlobalGuards로 등록한 것이 가장 먼저, 메서드 데코레이터가 가장 나중에 실행된다.

← 이전 글NestJS Exception Filter — 예외를 중앙에서 처리하는 방법
다음 글 →NestJS Repository — 데이터베이스와 직접 통신하는 계층