[NestJS] 요청 라이프사이클 마스터 가이드: 미들웨어부터 인터셉터까지
1. 🏢 비유로 이해하는 NestJS 오피스 빌딩
기술적인 용어를 잠시 내려놓고, NestJS 서버를 하나의 거대한 회사 건물이라고 상상해 봅시다.
- Middleware (건물 정문 보안요원)
- 건물의 입구에서 모든 입장객을 체크합니다. "위험물(CORS/잘못된 바이트)은 없나요?", "어디서 오셨나요?(로깅)"
- 이 요원은 여러분이 몇 층의 어느 사무실을 가려는지 구체적으로는 관심이 없습니다. 오직 건물 진입 가능 여부만 봅니다.
- Guard (사무실 카드키 보안문)
- 특정 사무실(컨트롤러)에 들어가기 직전, 복도에 있는 보안 장치입니다.
- "아, 개발팀 사무실이군요? 카드키(JWT 토큰) 찍어주세요. 권한이 없으면 못 들어갑니다."
- Interceptor - Pre (비서/안내 데스크)
- 사무실 안으로 들어가기 직전, 비서가 업무를 도와줍니다.
- "담당자님이 지금 바쁘시네요. 지난번에 물어보신 답변이 여기 있으니 이거 가져가세요(캐시)." 또는 "지금부터 상담 시간을 기록하겠습니다(로깅 시작)."
- Pipe (서류 검토 및 교정)
- 담당자 책상에 서류(데이터)를 올리기 전 최종 검토 단계입니다.
- "날짜가 그냥 글자로 적혀있네요? 담당자님이 보기 좋게 날짜 객체로 고쳐드릴게요(변환)." "어? 형식이 틀렸네요? 다시 써오세요(검증)."
- Controller & Service (실제 업무 담당자)
- 파이프가 다듬어준 완벽한 서류를 보고 실제로 로직을 처리하는 실무자입니다.
- Interceptor - Post (나갈 때 주는 회의록/봉투)
- 업무가 끝나고 나가는 사람에게 마지막 처리를 해줍니다.
- "상담 끝났습니다. 여기 결과물(응답 데이터)을 예쁜 봉투(공통 응답 포맷)에 담아드릴게요."
2. 라이프사이클 상세 분석
2.1. Middleware: 가장 바깥쪽의 필터
미들웨어는 요청(req)과 응답(res) 객체 사이에서 동작하는 함수입니다.
- 핵심:
next()를 호출하여 다음 단계로 넘기거나, 응답을 종료할 수 있습니다.
- 활용: CORS, 공통 로깅, 바디 파싱.
2.2. Guard: 인가(Authorization) 계층
가드는 미들웨어와 달리 실행될 메서드의 정보(Context)를 알고 있습니다.
- 핵심:
canActivate()가 true일 때만 컨트롤러로 진입을 허용합니다.
- 활용: JWT 토큰 검증, Role 기반 접근 제어(RBAC).
2.3. Interceptor: 전후처리 마술사
RxJS를 활용하여 비동기 흐름을 제어하고 응답 데이터를 변형합니다.
- 활용: 응답 포맷 통일, 캐싱, 로깅 시작/종료 처리.
2.4. Pipe: 데이터 정제 및 역직렬화
컨트롤러 인자를 대상으로 변환(Transformation)과 검증(Validation)을 수행합니다.
- 활용:
ValidationPipe를 이용한 DTO 검증, ParseIntPipe를 이용한 형변환.
3. 핵심 비교 요약
| 구분 | Middleware | Guard | Interceptor | Pipe |
|---|
| 비유 | 건물 정문 보안 | 사무실 카드키 | 비서/안내 데스크 | 서류 검토인 |
| 주요 기술 | Express 함수 | NestJS 클래스 | RxJS (Observable) | DTO & Metadata |
| 핵심 역할 | HTTP 헤더 조작 | 인증/권한 부여 | 응답 가공/로깅 | 데이터 검증/변환 |
4. 마치며
NestJS의 요청 라이프사이클을 이해한다는 것은 "책임의 분리"를 실천한다는 뜻입니다. 적절한 로직을 적절한 위치(미들웨어, 가드, 파이프 등)에 배치하면 코드는 자연스럽게 깨끗해지고 유지보수는 쉬워집니다.
이제 각 단계의 존재 이유를 명확히 이해하고, 여러분의 프로젝트에 최적화된 파이프라인을 설계해 보세요!
참고 자료: