Server/Node.js

NodeJS - 전역 예외 핸들러 구현 (Custom global exception handler)

JaeHoney 2021. 12. 29. 20:03

전역 예외 핸들러

저의 경우 Sequelize + express + nodejs의 프로젝트를 하고 있었는데, Sequelize가 500번대 예외를 뱉는 경우가 많았습니다. 해당 부분은 App단에서 최대한 검증을 해서 요청을 보내면 좋겠지만, 동시성 문제로 어쩔 수 없이 예외가 발생하기도 합니다.

 

요즘은 500번대 에러는 핸들링을 하는 것을 원칙으로 하는 기업이 많은 걸로 알고 있습니다. 특히 네이버 특정 계열사 Open API Reference에 보면 500번대 에러가 나오면 제보해달라는 내용이 있기도 하기도 합니다.

 

따라서, 해당 예외를 핸들링하고 싶었는데, 각 메서드에 여러개의 예외처리를 전부 공통적으로 붙이면 유지보수성이 떨어지니까, 전역 범위로 적용해야 했습니다. 스프링은 @ControllerAdvice나 @ExceptionHandler을 사용해서 간단하게 만들 수 있지만, NodeJS에서는 직접 구현을 해야 했습니다.

 

구현

import {NextFunction, Request, Response} from "express";
import HttpException from "../libraries/http/HttpException";
import HttpStatusCode from "../libraries/http/HttpStatusCode";
import {ForeignKeyConstraintError, UniqueConstraintError, ValidationError} from "sequelize";

export const globalExceptionHandler = () => {
    return function (error: Error, req: Request, res: Response, next: NextFunction) {
        if(error instanceof HttpException ) {
            res.status(error.status).json(error.json());
        } else {
            if(
                error instanceof ValidationError ||
                error instanceof ForeignKeyConstraintError ||
                error instanceof UniqueConstraintError
            ) {
                setErrorResponse(res, HttpStatusCode.BAD_REQUEST, "Bad request");
            }
            else setErrorResponse(res, HttpStatusCode.SERVER_ERROR, error.toString());
        }
        return next();
    };
}

function setErrorResponse(res: Response, code: number, message: string) {
    res.status(code).json({ status: code, message: message });
}

typescript 예제입니다. 예외가 발생했을 때 이 메서드가 실행되게 하면 됩니다.

메서드를 간략히 소개드리자면, 예외가 발생했을 때 HttpExcepetion의 종류면 그대로 뱉고, Sequelize.ValidationError, Sequelize.ForeignKeyConstraintError면 400번대 에러를 뱉도록 예외 처리를 커스터마이즈(customize)하고 있습니다.

 

ErrorResponse부분은 각 프로젝트의 API 스펙에서 정의한 에러 메시지 형태를 사용하면 됩니다!

 

적용

const app = express();
app.use(globalExceptionHandler());

app.ts에서 app.use()를 사용해서 위 코드 처럼 전역 예외처리 핸들러를 미들웨어로 사용하게 할 수 있습니다.

 

app.use()에 들어가는 Arrow function에 request, response, nextFunction, error 총 4개의 파라미터를 갖는 함수를 지정해주면, 예외가 발생했을 때 해당 미들웨어를 실행합니다.

 

감사합니다 !