[Nest] Exception filters

Younghwan Cha·2023년 3월 11일
0

Nest.js

목록 보기
10/27
post-thumbnail

nest.js 에서는 내장 global execption filter 를 사용하여 HttpException 을 처리한다.
application code 단에서 handle 되지 않은 예외들은 nest.js 의 내장 exceptions layer 가 인지하고 이를 유저가 이해하기 쉬운 언어의 response 로 전달한다. HttpException class 나 HttpException 을 상속받아 정의한 class 어느 것에도 정의되어 있지 않은 error 를 마주할 경우엔 내장 exception filter 가 아래 JSON response 를 반환한다.

{
  "statusCode": 500,
  "message": "Internal server error"
}

이 global exception filter 는 기본적으로 http-errors library 를 지원하기 때문에 statusCodemessage 속성을 갖은 exception 들은 위의 InternalServerErrorException 대신 정상적인 exception response 값이 반환될 것이다.


HttpException constructor

import { HttpException, HttpStatus } from '@nestjs/commmon';

async findAll() {
	throw new HttpException('message here', HttpStatus.NOT_FOUND);
}

// execption response
{
    "statusCode": 404,
    "message": "message here"
}

HttpException contructor 는 두개의 필수 인자를 갖는다.

  • response
    JSON response body 를 정의: <string | object>
  • status
    HTTP status code ( best practice to use HttpStatus from @nestjs/common )
  • options( optional )
    logging 을 위하여 cause 를 통해서 error 와 관련된 부가적인 정보를 제공

또한, JSON response body 는 다음 두개의 default 값을 갖는다.

  • statusCode
    status 인자로 전달 받은 HTTP status code
  • message
    status 에서 전달 받은 HTTP status code 에 기반한 short description

BadRequestException

nest.js 의 코드를 보면 이해가 좀 더 쉽다.

// bad-request.exception.d.ts

export declare class BadRequestException extends HttpException {
    /**
     * Instantiate a `BadRequestException` Exception.
     *
     * @example
     * `throw new BadRequestException()`
     *
     * @usageNotes
     * The HTTP response status code will be 400.
     * - The `objectOrError` argument defines the JSON response body or the message string.
     * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
     *
     * By default, the JSON response body contains two properties:
     * - `statusCode`: this will be the value 400.
     * - `message`: the string `'Bad Request'` by default; override this by supplying
     * a string in the `objectOrError` parameter.
     *
     * If the parameter `objectOrError` is a string, the response body will contain an
     * additional property, `error`, with a short description of the HTTP error. To override the
     * entire JSON response body, pass an object instead. Nest will serialize the object
     * and return it as the JSON response body.
     *
     * @param objectOrError string or object describing the error condition.
     * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
     */
    constructor(objectOrError?: string | object | any, descriptionOrOptions?: string | HttpExceptionOptions);
}
throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description' })

> {
  	"message": "Something bad happened",
  	"error": "Some error description",
  	"statusCode": 400,
  }

Exception filters

built-in exception filter 이외에도 전달받는 response 에 날짜 정보를 추가하는 등의 추가적인 처리를 원할 때
exception filter 를 추가하여 구현 할 수 있다.

@UseFilters()

// global-scope 에 적용
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(HttpExceptionFilter);
  await app.listen(3000);
}
bootstrap();

// controller-scope 에 적용
@UseFilters(HttpExceptionFilter)
export class CatsController {}

// method-scope 에 적용
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}

@UseFilters(new HttpExceptionFilter()) vs @UseFilters(HttpExceptionFilter)
둘다 사용이 가능하지만, HttpExceptionFilter 와 같이 class 로 전달할 경우
nest 가 전체 module 에서 동일한 class 로 여러개의 instance 를 생성해 사용 할 수 있기 때문에 메모리 사용 측면에서 이점이있다.

global filter

http 이외의 error 또한 모두 filter 하려면 아래를 참고하도록 하자

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

[all exception filter] https://docs.nestjs.com/exception-filters#catch-everything

[nestjs Execption filters] https://docs.nestjs.com/exception-filters

profile
개발 기록

0개의 댓글