NestJS Tutorial (6) - Exception Filter

Hoony·2023년 6월 27일
0

NestJS

목록 보기
6/8


Exception Filter

NestJS는 기본적인 Exception을 처리하는 Exception Layer가 존재합니다.

@nestjs/common 에 있는 HttpException Class를 사용하면 표준 예외 처리가 가능합니다.

@Get()
async findAll(){
	throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}

// 예외 출력
//{
//  "statusCode": 403,
//  "message": "Forbidden"
//}


Custom Exception

표준 HttpException을 상속받아 Custome Exception을 생성할 수 있습니다.

export class ForbiddenException extends HttpException {
  constructor() {
    super('Forbidden', HttpStatus.FORBIDDEN);
  }
}
@Get()
async findAll() {
  throw new ForbiddenException();
}

Cause - 오류 설명 제공

cause 매개변수를 통해 오류설명을 제공할 수 있습니다.

throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description' })

// 출력
// {
//   "message": "Something bad happened",
//   "error": "Some error description",
//   "statusCode": 400,
// }


예외 필터 생성

NestJS에서 제공하는 기본 예외 필터를 제공하지만, 새로운 예외 필터가 필요할 수 있습니다.

그럴 경우 ExceptionFilter interface를 구현하여 새로운 예외 필터를 만들어 사용하면 됩니다.

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

@Catch 데코레이터를 통해 특정 예외만 필터가 처리하도록 합니다.

이때 쉼표로 구분지어 리스트로 매개변수 입력이 가능하여, 여러 유형 예외 처리가 가능합니다.

exception : 현재 처리 중인 예외 객체

host : ArgumentHost : 요청 및 응답 객체에 대한 참조를 가진 객체



예외 필터 바인딩 - 필터 적용

@UseFilters 데코레이터를 통해 필터 바인딩이 가능합니다.

이때 바인딩 범위는 작게는 컨트롤러 함수 단위부터 전역 단위까지 가능합니다.

  • 가능한 경우 인스턴스 대신 클래스를 사용하여 필터를 적용하는 것이 좋습니다.
  • 전체 모듈에서 동일한 클래스 인스턴스를 재사용 하므로 메모리 사용량을 줄일 수 있습니다.

컨트롤러 특정 함수에 적용

@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}

컨트롤러 전체에 적용

@UseFilters(new HttpExceptionFilter())
export class CatsController {}

전역 단위로 적용

//main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();


모든 예외 처리

위의 예외 필터에서는 @Catch(HttpException) 데코레이터를 통해 HttpException 만 처리합니다.

이때 @Catch() 매개변수를 비워두면 모든 Exception에 대해 처리가 가능합니다.

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

  catch(exception: unknown, host: ArgumentsHost): void {
    // In certain situations `httpAdapter` might not be available in the
    // constructor method, thus we should resolve it here.
    const { httpAdapter } = this.httpAdapterHost;

    const ctx = host.switchToHttp();

    const httpStatus =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const responseBody = {
      statusCode: httpStatus,
      timestamp: new Date().toISOString(),
      path: httpAdapter.getRequestUrl(ctx.getRequest()),
    };

    httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
  }
}

이때 생성자로 HttpAdapterHost를 넘겨줘야하므로 다음과 같이 설정한다.

import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/exception/all-exception.filter';
import { HttpExceptionFilter } from './common/exception/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const httpAdapter = app.get(HttpAdapterHost);
  app.useGlobalFilters(
    new HttpExceptionFilter(),
    new AllExceptionsFilter(httpAdapter),
  );
  await app.listen(3000);
}
bootstrap();


기본 내장 ExceptionFilter 확장

NestJS에는 기본 예외 처리 레이어가 존재한다.

이를 확장해서 사용하기 위해선 BaseExceptionFilter를 다음과 같이 확장하면 된다.

import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';

@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    super.catch(exception, host);
  }
}

이때 생성자로 AbstractHttpAdapter를 넘겨줘야하므로 다음과 같이 설정한다.

import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/exception/all-exception.filter';
import { HttpExceptionFilter } from './common/exception/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const { httpAdapter }  = app.get(HttpAdapterHost);
  app.useGlobalFilters(
    new HttpExceptionFilter(),
    // new AllExceptionsFilter(httpAdapter),
    new AllExceptionsFilter2(httpAdapter),
  );
  await app.listen(3000);
}
bootstrap();

profile
Just Do it!

0개의 댓글

관련 채용 정보