NestJS Exception Filters 완벽 정리 (라이프사이클부터 내부 동작까지)

2025. 2. 12. 10:36·📂 Backend Engineering
728x90
반응형

NestJS Exception Filters 정리

NestJS에는 애플리케이션 전역에서 처리되지 않은 모든 예외를 담당하는 예외 계층(Exception Layer) 이 내장되어 있습니다.
애플리케이션 코드에서 예외가 처리되지 않고 발생하면, 이 계층이 이를 포착하여 사용자 친화적인 HTTP 응답을 자동으로 반환합니다.

공식 문서: https://docs.nestjs.com/exception-filters


🌠 목차

  • NestJS 요청 라이프사이클
  • Exception Filters의 주요 목적
  • Exception Filters가 에러를 잡을 수 있는 이유
  • 예외 처리 방법들
  • Exception Filters를 활용한 커스텀
  • Filters vs Pipes
  • Interceptor 개념 정리
  • Guard 개념 정리
  • Pipes와 Query / Body 처리 방식

NestJS 요청 라이프사이클

클라이언트 요청이 컨트롤러에 도달하기까지의 흐름은 다음과 같습니다.

  1. 클라이언트 요청
  2. 미들웨어 실행 (로깅, 인증 등)
  3. 가드 실행 (권한 체크: AuthGuard, AdminGuard 등)
  4. 인터셉터 시작
  5. 파이프 실행 (데이터 변환 / 유효성 검사)
  6. 컨트롤러 메서드 실행
  7. 서비스 로직 실행
  8. 인터셉터 종료
  9. 응답 반환

⚠️ 에러가 발생하면?

위 과정 중 어디에서든 예외가 발생하면

  • Exception Filter가 에러를 캐치
  • 적절한 에러 응답을 클라이언트에 반환

Exception Filters의 주요 목적

1️⃣ 에러 캐치

  • 요청 라이프사이클 전역에서 발생한 예외를 처리

2️⃣ 에러 커스텀

  • 에러 응답 포맷을 프로젝트 기준에 맞게 통일
  • 메시지, timestamp, path 등 추가 가능

Exception Filters가 에러를 잡을 수 있는 이유

핵심은 @Catch() 데코레이터입니다.

export declare function Catch(
  ...exceptions: Array<Type<any> | Abstract<any>>
): ClassDecorator;

의미 정리

  • ...exceptions
    • 여러 개의 예외 타입을 Rest Parameter로 전달 가능
  • Type
    • 구체적인 클래스
  • Abstract
    • 추상 클래스 또는 인터페이스
  • 반환값
    • ClassDecorator
// Type 예시
class HttpException {}

// Abstract 예시
abstract class BaseException {}
interface IException {}

👉 즉, 특정 예외 타입만 골라서 필터링 가능합니다.


Node Modules 내부 동작 구조

BaseExceptionFilter

기본 예외 처리 로직을 담당하는 추상 필터 클래스입니다.

export declare class BaseExceptionFilter<T = any>
  implements ExceptionFilter<T> {
  catch(exception: T, host: ArgumentsHost): void;
}
  • 기본 catch() 구현 제공
  • 알 수 없는 에러 처리 로직 포함

BaseExceptionFilterContext

  • 필터 인스턴스 생성 및 관리
  • DI 컨테이너와 연동

ExceptionsHandler

예외 처리 시스템의 중심

  • 발생한 예외를 적절한 필터로 라우팅
export declare class ExceptionsHandler extends BaseExceptionFilter {
  next(exception: any, ctx: ArgumentsHost): void;
}

전체 흐름 요약

예외 발생
  ↓
Router / Middleware (최초 캐치)
  ↓
ExceptionsHandler
  ↓
BaseExceptionFilterContext
  ↓
BaseExceptionFilter or ExternalExceptionsFilter

예외 처리 방법들

기본 제공 방식

throw new HttpException('접근 금지!', HttpStatus.FORBIDDEN);
{
  "statusCode": 403,
  "message": "접근 금지!"
}

하지만 응답을 더 커스터마이징하고 싶다면?

➡️ Exception Filter를 사용합니다.


Exception Filters를 활용한 커스텀

@Catch(HttpException)
export class MyExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const response = host.switchToHttp().getResponse();

    response.status(403).json({
      statusCode: 403,
      timestamp: new Date(),
      message: '죄송합니다. 접근 권한이 없습니다.',
      path: '/admin',
    });
  }
}

언제 쓰면 좋을까?

  • 에러 로깅을 하고 싶을 때
  • 에러 응답 포맷을 통일하고 싶을 때
  • 특정 예외만 다르게 처리하고 싶을 때

여러 예외 처리

@Catch(HttpException, ValidationError)
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {}
}
@Catch()
export class CatchAllFilter implements ExceptionFilter {}

Exception Filters vs Pipes

Exception Filters

  • 발생한 예외를 처리
  • 클라이언트에 반환할 응답을 결정

Pipes

  • 컨트롤러 진입 이전에 실행
  • 데이터 변환 / 유효성 검사

❗ Pipe에서 발생한 예외도 결국 Exception Filter에서 처리됩니다.


Interceptor 정리

역할

  • 메서드 실행 전/후 로직 추가 (AOP)
  • 응답 변환
  • 예외 변환
  • 캐싱, 로깅, 타임아웃 처리

구조

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    console.log('Before...');

    return next.handle().pipe(
      tap(() => console.log(`After... ${Date.now() - now}ms`)),
    );
  }
}

Guard 정리

Guard란?

  • 라우트 핸들러 실행 여부를 결정
  • 권한, 인증, 역할 기반 제어
export interface CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean>;
}

Guard vs Middleware

구분GuardMiddleware

실행 시점 핸들러 직전 라우트 이전
역할 접근 허용 여부 결정 요청/응답 객체 수정
Context ExecutionContext 접근 가능 핸들러 정보 접근 불가

Pipes와 Query / Body 처리

Query String

@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {}
{
  "statusCode": 400,
  "message": "Validation failed (numeric string is expected)",
  "error": "Bad Request"
}

👉 잘못된 값이면 컨트롤러 진입 자체를 막음

Body 처리

  • Pipe로 직접 검증 ❌
  • class-validator 사용 ⭕️
export class CreateEventBody {
  @IsUUID()
  uuid?: string;
}

마무리

  • Exception Filter는 에러 처리의 마지막 보루
  • Pipe / Guard / Interceptor와 함께 사용할 때 진짜 위력이 나옵니다

👍 글이 도움이 됐다면 좋아요 한 번 눌러주세요

관심 받는 거 좋아합니다 😄

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'📂 Backend Engineering' 카테고리의 다른 글

(공식문서) NestJS Pipes와 queryString, Body가 데이터 처리하는 방법  (1) 2025.02.18
테스트 코드 현실 적용기: Unit Testing 책을 통한 인사이트와 실무 경험  (0) 2025.01.29
[백엔드]기프티콘 도메인에 대한 이해 & 정리 & 회고  (0) 2024.05.11
[Cursor 페이지네이션] nestJS + Prisma - cursor 페이지네이션 방식 (성능 최적화, 직접 cursor 구현)  (1) 2024.03.31
RDB와 NoSql 비교 및 장점 | AWS에서 제공하는 NoSql은?  (0) 2024.03.15
'📂 Backend Engineering' 카테고리의 다른 글
  • (공식문서) NestJS Pipes와 queryString, Body가 데이터 처리하는 방법
  • 테스트 코드 현실 적용기: Unit Testing 책을 통한 인사이트와 실무 경험
  • [백엔드]기프티콘 도메인에 대한 이해 & 정리 & 회고
  • [Cursor 페이지네이션] nestJS + Prisma - cursor 페이지네이션 방식 (성능 최적화, 직접 cursor 구현)
foodev
foodev
이것저것 개발과 이것저것 리뷰 합니다.
    반응형
    250x250
  • foodev
    개발 개맛집
    foodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (104) N
      • ⭐ Featured (4)
      • 📂 Backend Engineering (36)
      • 📂 Troubleshooting & Ops (10)
      • 📂 Infra & System (7) N
      • 📂 Reflections (21)
        • Year-in-Review (5)
        • Work & Career (10)
        • Lessons Learned (6)
      • 📂 Team Journal (10)
      • 📂 Archive (16)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    validation failed (numeric string is expected)
    서이추
    해피해킹 커스텀
    githubaction 라벨 배포
    nestjs pipe
    azure ci/cd
    Azure 로그 최소 저장 30일
    di의존성
    QueryDSL
    해피해킹 방향키
    해피해킹 카라비너
    해피해킹 키매핑
    인프라 로그 저장 비용 감소하는 방법
    토이프로젝트개발일지
    스냅샷과 히스토리
    db 날림
    di란
    Azure log 비용 줄이기
    typedi란
    githubaction 라벨 ci/cd
    db 초기화
    스냅샷과히스토리성 차이
    JPA
    di동작원리
    nestjs pipe body
    해피해킹 꿀팁
    db 날린 썰
    개발썰
    창업패키지후기
    typedi 동작원리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
foodev
NestJS Exception Filters 완벽 정리 (라이프사이클부터 내부 동작까지)
상단으로

티스토리툴바