💻 개발/프레임워크

(공식문서) NestJS Exception filters

foodev 2025. 2. 12. 10:36
728x90

Nestjs Exception filters 첫 문장

Nest에는 애플레킹션 전체에서 처리되지 않은 모든 예외를 처리하는 예외 계층이 내장 되어 있습니다.
애플리케이션 코드에서 처리되지 않은 예외가 발생하면 이 계층에서 이를 포착하여 적절한 사용자 친화적인 응답을 자동 전송합니다.

 

 

 

관련된 링크: https://docs.nestjs.com/exception-filters

 

 

🌠 목차
✅ NestJS 요청 라이프 사이클
✅ Exception filters의 주요목적
✅ Exception filters가 에러를 잡을 수 있는 이유
✅ 예외 처리 방법들 
✅ Exception filters를 활용한 커스텀 
✅ 필터와 파이프 차이

NestJS 요청 라이프 사이클


클라이언트의 요청이 컨트롤러에 도달하기까지의 플로우

1. 클라이언트 요청이 들어옴

2. 미드루에어 실행(로깅, 인증 등)

3. 가드 실행(권한 체크 authGuard, adminGuard 등)

4. 인터셉터 시작

5. 파이프 실행(데이터 변환/유효성 검사)

6. 컨트롤러 메서드 실행 

7. 서비스 로직 실행(service)

8.인터셉터 종료

9. 응답 반환 

 

만약 이 과정 중 어디서든 에러가 발생하면

- 예외 필터가 에러를 잡아서 처리

- 적절한 에러 응답을 클라이언트에게 반환 

 

 

 

Exception filters의 주요 목적 


에러 캐치 

요청 라이프 사이클 전역에서 에러 발생 시 캐치

에러 커스텀

에러 응답을 커스터마이징

 

Exception filters잡을 수 있는 이유


@Catch 데코레이터

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

설명

...exceptions: Rest 파라미터로, 여러 개의 예외 타입을 받을 수 있습니다

Array<Type<any> | Abstract<any>>: 배열의 각 요소는 Type이거나 Abstract 타입입니다.

:ClassDecorator: 반환 타입 

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

 

Type과 Abstract는 다음과 같은 의미를 가집니다.

// Type: 구체적인 클래스 타입
class HttpException {} 
// 이런 실제 클래스를 의미

// Abstract: 추상 클래스나 인터페이스
abstract class BaseException {}
interface IException {}
// 이런 추상적인 타입을 의미

 

에러 커스텀

에러 응답을 커스터마이징

 

NodeModules.Exception filters 내부 동작 원리


base-exception-filter.d.ts 

기본적인 예외 처리 로직이 있는 필터의 기본 클래스

catch()메소드의 기본 구현 제공

import { ArgumentsHost, ExceptionFilter, HttpServer } from '@nestjs/common';
import { AbstractHttpAdapter } from '../adapters';
import { HttpAdapterHost } from '../helpers/http-adapter-host';
export declare class BaseExceptionFilter<T = any> implements ExceptionFilter<T> {
    protected readonly applicationRef?: HttpServer;
    private static readonly logger;
    protected readonly httpAdapterHost?: HttpAdapterHost;
    constructor(applicationRef?: HttpServer);
    catch(exception: T, host: ArgumentsHost): void;
    handleUnknownError(exception: T, host: ArgumentsHost, applicationRef: AbstractHttpAdapter | HttpServer): void;
    isExceptionObject(err: any): err is Error;
    /**
     * Checks if the thrown error comes from the "http-errors" library.
     * @param err error object
     */
    isHttpError(err: any): err is {
        statusCode: number;
        message: string;
    };
}

노드 모듈의 core/base-exception-fitler.ts로 이동하여 NestJS의 @Catch 데코레이터 구현부입니다

 

/base-exception-filter-context.d.ts

필터 인스턴스의 생성과 관리를 담당

DI 컨테이너와 상호작용

import { Type } from '@nestjs/common/interfaces';
import { ExceptionFilter } from '@nestjs/common/interfaces/exceptions/exception-filter.interface';
import { ContextCreator } from '../helpers/context-creator';
import { NestContainer } from '../injector/container';
import { InstanceWrapper } from '../injector/instance-wrapper';
export declare class BaseExceptionFilterContext extends ContextCreator {
    private readonly container;
    protected moduleContext: string;
    constructor(container: NestContainer);
    createConcreteContext<T extends any[], R extends any[]>(metadata: T, contextId?: import("../injector/instance-wrapper").ContextId, inquirerId?: string): R;
    getFilterInstance(filter: Function | ExceptionFilter, contextId?: import("../injector/instance-wrapper").ContextId, inquirerId?: string): ExceptionFilter | null;
    getInstanceByMetatype(metatype: Type<unknown>): InstanceWrapper | undefined;
    reflectCatchExceptions(instance: ExceptionFilter): Type<any>[];
}



exceptions-handler.ts

전체 예외 처리 시스템의 중심

발생한 예외를 적절한 필터로 라우팅 즉, 라우팅 핸들러 역할을 함 

 

import { HttpException } from '@nestjs/common';
import { ArgumentsHost } from '@nestjs/common/interfaces/features/arguments-host.interface';
import { ExceptionFilterMetadata } from '@nestjs/common/interfaces/exceptions/exception-filter-metadata.interface';
import { BaseExceptionFilter } from './base-exception-filter';
export declare class ExceptionsHandler extends BaseExceptionFilter {
    private filters;
    next(exception: Error | HttpException | any, ctx: ArgumentsHost): void;
    setCustomFilters(filters: ExceptionFilterMetadata[]): void;
    invokeCustomFilters<T = any>(exception: T, ctx: ArgumentsHost): boolean;
}

 

external-exceptions-filter.d.ts

외부 라이브러리나 시스템에서 발생하는 예외 처리 

 

상호작용의 흐름

예외 발생

ExceptionsHandler

BaseExceptionFilterContext (필터 인스턴스 생성/관리)

BaseExceptionFilter 또는 ExternalExceptionsFilter (실제 예외 처리)

 

실제 에러 캐치는 Router/Middleware 레벨에서 


https://github.com/nestjs/nest/blob/master/packages/core/router/router-execution-context.ts

 

nest/packages/core/router/router-execution-context.ts at master · nestjs/nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀 - nestjs/nest

github.com

 

 

위에서 살펴봤던 NestJS의 라이프사이클을 떠올려 봅시다.

 

실제 에러캐치는 Router/Middleware 레벨에서 "최초"로 캐치 됩니다.

캐치된 에러는 ExceptionsHandler로 전달됩니다.

 

 

 

예외 처리 방법들 


기본제공

기본 제공되는 HttpException 사용

내장 함수들

BadRequestException()

Unauthorized()

 

// 방법 1: 간단히 에러 던지기
throw new HttpException('접근 금지!', HttpStatus.FORBIDDEN);

// 결과
{
  "statusCode": 403,
  "message": "접근 금지!"
}

 

만약 위의 응답 결과에 timestap나 추가적인 메시지를 던져주고 싶을 때 

사용하는 것이 Exception filters

 

 

Exception filters를 활용한 커스텀 


response 커스텀 코드

@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"
    });
  }
}

 

  • 에러 로깅을 하고 싶을 때
  • 에러 응답 형식을 프로젝트 표준으로 통일하고 싶을 때
  • 특정 상황에서 다른 형태의 에러 응답을 주고 싶을 때

 

종류별 에러 잡기

// HttpException만 잡기
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    // 처리 로직
  }
}

// 여러 종류의 에러 잡기
@Catch(HttpException, ValidationError)
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    // 처리 로직
  }
}

// 모든 종류의 에러 잡기
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    // 처리 로직
  }
}

Exception filters와 Pipe


NestJS에서는 Exception filters와 filters의 개념이 동일하다.

Exception filter의 동일

 

Exception filters와 Pipe

Exception filters:

- 예외 필터가 에러를 잡아서 처리

- 적절한 에러 응답을 클라이언트에 반환 

 

Pipe

- 데이터가 컨트롤러에 전달되기 전에 실행 (데이터 검증/변환)

 

 

 

 

 

 

 

글 잼나게 보셨으면 좋아요 눌러주고 가세요

관심 받는거 좋아합니다

 

 

728x90