ourlim-Exception Filters 문제 수정

Yi Kanghoon·2023년 1월 1일
2

Exception filters

nest에는 처리하지 않은 '모든'예외를 처리하는 예외처리 레이어가 있다. 즉, 내가 따로 쓰지 않으면 자동으로 적절한 응답을 만들어 보낸다.

Base exceptions

nest에는 내장된 HttpException클래스가 있고, 해당 내장 클래스를 이용하면

{
  "status": 403,
  "error": "This is a custom message"
}

와 같은 응답을 자동으로 구성해 준다. (물론 생성자에 에러 코드와 메시지는 적절히 넣어야 겠지만)
해당 구조를 따라가기위해 Ourlim에서도 아래와 같이 이를 상속받는 커스텀 exception을 만드는 방식으로 예외처리 구조를 구현했다.

import { HttpException, HttpStatus } from "@nestjs/common";

export class NoUserInfoException extends HttpException {
  constructor(code: RecruitmentsExceptionType) {
    super(types[code], HttpStatus.BAD_REQUEST);
  }
}

const types = {
  R014: {
    code: "R014",
    message: "User info is needed to use 'isAuthor', 'isFavorite', or 'isApplied'",
  },
} as const;

type RecruitmentsExceptionType = keyof typeof types;

또한, 이렇게 만든 커스텀 exception과 class-validator에 의한 exception, 그리고 route 문제로 인한 not-found exception의 응답 json 객체를 통일할 필요가 있었고, exception filter를 이용해 모든 'http' 예외를 잡아서 객체 통일 로직을 수행해야 했다. (문제의 시작이다....하)

exception filter

내장 필터가 많은 경우를 잘 처리해 주지만 완전히 제어하지는 못하고, 우리의 경우와 같이 json스키마를 통일하거나 로깅을 추가할 필요가 있을때 내장 필터를 상속받는 커스텀 필터를 구현 할 수 있다.
그리고 함께 사용되는 것이 @Catch()데코레이터....

Ourlim에서는

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

type ExceptionResponse = {
  code: string;
  message: string | string[];
  error?: { entity: any; identifier: number | string } | string;
  statusCode: number;
};
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const res = ctx.getResponse<Response>();
    const response = exception.getResponse() as ExceptionResponse;
    if (!response.code) {
      if (response.message) {
        response.code = "I001";
      }
      response.error = undefined;
      response.statusCode = undefined;
    }
    if (!(exception instanceof HttpException)) {
      exception = new InternalServerErrorException();
    }
    res.status((exception as HttpException).getStatus()).json(response);
  }
}

와 같이 구현했고, 정상적으로 잘 작동하는 것으로 보여 merge완료 후 배포하려고 했으나 exception.getResponse()부분에서 에러가 발생했다.

원인

@Catch() 데코레이터는 파라미터로 주어진 형식의 예외를 잡아서 예외필터에 바인딩해준다. 하지만 위의 코드에서는 파라미터가 비어있었고, 모든 형식의 예외를 잡아서 처리를 시도했던 것이다.
개발환경에서는 발생하지 않긴 했는데, 프로덕션 환경에서 발생한 http 예외가 아닌 예외가 발생하면서 문제가 생겼던 것.

공식문서를 잘 읽자.....

profile
Full 'Snack' Developer

1개의 댓글

오홍 좋은 주제군요!

답글 달기