Post

오류를 처리하는 방법

node.js에서 가장 많이 사용되는 오류를 처리하는 방식

1. 객체를 활용

■ 장점

  • 오류 유형과 메세지를 빠르게 조회할 수 있음
  • 중앙 집중식으로 오류 코드와 메세지를 관리할 수 있음

■ 단점

  • 오류 유형이 추가될 때마다 객체를 업데이트 해야함

■ 사용 상황

  • 오류 유형이 많지 않고, 특정한 오류 메세지나 코드에 대한 빠른 조회가 필요한 경우

■ 사용 방법

① 오류 정보를 담은 객체 만들기

1
2
3
4
5
6
7
8
9
10
const errors = {
  ER_BAD_FIELD_ERROR: {
    code: StatusCodes.BAD_REQUEST,
    message: "잘못된 필드를 참조"
  },
  ER_NO_SUCH_TABLE: {
    code: StatusCodes.BAD_REQUEST,
    message: "존재하지 않는 테이블을 참조"
  }
};

② 객체를 사용하여 오류를 처리하기

1
2
3
4
5
6
7
8
9
const handleError = (res, error) => {
  console.error(error);

  const message = errors[error.name]?.message || "내부 서버 오류";
  const statusCode =
    errors[error.name]?.code || StatusCodes.INTERNAL_SERVER_ERROR;

  res.status(statusCode).send({ message });
};

2. switch문을 사용

■ 장점

  • 로직이 직관적

■ 단점

  • 코드가 길어질 수 있음
  • 오류 유형이 많을수록 관리가 어려워짐

■ 사용 상황

  • 오류 처리가 간단하고 명확한 조건 분기를 원할 때 사용

■ 사용 방법

① 오류 처리 함수 구현 (switch문 사용)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function handleError(errorType, res) {
  switch (errorType) {
    case "ER_BAD_FIELD_ERROR":
      res
        .status(StatusCodes.BAD_REQUEST)
        .send({ message: "잘못된 필드를 참조하였습니다." });
      break;
    case "ER_NO_SUCH_TABLE":
      res
        .status(StatusCodes.BAD_REQUEST)
        .send({ message: "존재하지 않는 테이블을 참조하였습니다." });
      break;
    default:
      res
        .status(StatusCodes.INTERNAL_SERVER_ERROR)
        .send({ message: "내부 서버 오류" });
  }
}

3. 커스텀 에러 클래스 사용

■ 장점

  • 각 오류 유형별로 명확한 클래스를 가짐 (직관적)
  • 오류 유형에 따라 다른 처리 로직을 쉽게 구현할 수 있음
  • 에러 인스턴스에 추가적인 정보를 포함시킬 수 있음

■ 단점

  • 유형별로 클래스가 생기기때문에 많은 클래스를 생성하고 관리해야함

■ 사용 상황

  • 대규모 애플리케이션에서 오류를 세분화하여 관리할 때
  • 추가적인 에러 정보를 포함시켜야할 때

■ 사용 방법

① BadRequestError 클래스 정의

  • nodejs의 Error에서 확장
1
2
3
4
5
6
7
8
class BadRequestError extends Error {
  constructor(message) {
    super(message);
    this.statusCode = StatusCodes.BAD_REQUEST;
  }
}

module.exports = { BadRequestError };

② 오류 생성

1
2
3
4
5
const { BadRequestError } = require("./errors");

if (!bookId) {
  throw new BadRequestError("잘못된 형식의 book id 값");
}

③ 에러 처리 미들웨어 등록하기

router 가장 마지막에 작성

1
2
3
4
5
6
7
8
// app.js
const express = require("express");
const app = express();

// 여러개의 router

// 에러 처리 미들웨어 등록 및 사용
app.use(handleError);

④ 에러 처리 미들웨어에서 오류 처리하기

err, req, res, next의 인자를 가짐

1
2
3
4
5
6
7
8
9
10
11
app.use((err, req, res, next) => {
  // 커스텀한 BadRequestError 오류 처리하기
  if (err instanceof BadRequestError) {
    return res.status(err.statusCode).json({ message: err.message });
  }

  // 기타 오류처리
  return res
    .status(StatusCodes.INTERNAL_SERVER_ERROR)
    .json({ message: err.message });
});

또는

Custom Error를 만들고, 각 클래스를 Custom Error를 확장해서 추가적인 에러 정보 포함시키기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CustomError extends Error {
  constructor(message, errorCode, statusCode) {
    super(message);
    this.code = errorCode;
    this.statusCode = statusCode;
    Error.captureStackTrace(this, this.constructor);
  }
}

// Custorm Error 활용해서 오류 생성하기
class BadRequestError extends CustomError {
  constructor(message, errorCode) {
    super(message, errorCode, StatusCodes.BAD_REQUEST);
    this.name = this.constructor.name;
  }
}
class UnauthorizedError extends CustomError {
  constructor(message, errorCode) {
    super(message, errorCode, StatusCodes.UNAUTHORIZED);
    this.name = this.constructor.name;
  }
}

module.exports = { CustomError, BadRequestError, UnauthorizedError };

② 오류 생성

1
2
3
4
5
const { UnauthorizedError } = require("./errors");

if (!token) {
  throw new UnauthorizedError("토큰이 유효하지 않습니다.", "ER_INVALID_TOKEN");
}

③ 에러 처리 미들웨어 등록하기

router 가장 마지막에 작성

1
2
3
4
5
6
7
8
// app.js
const express = require("express");
const app = express();

// 여러개의 router

// 에러 처리 미들웨어 등록 및 사용
app.use(handleError);

④ 에러 처리 미들웨어에서 오류 처리하기

err, req, res, next의 인자를 가짐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const { StatusCodes } = require("http-status-codes");
const { CustomError } = require("./errors");

app.use((err, req, res, next) => {
  // 커스텀 오류 클래스 확인
  if (error instanceof CustomError) {
    return res.status(error.statusCode).send({
      error: {
        message: error.message,
        code: error.code,
        status: error.statusCode
      }
    });
  }

  // 기타 오류 처리
  res.status(statusCodes.INTERNAL_SERVER_ERROR).send({
    error: {
      message: err.message || "서버 내부 오류가 발생했습니다.",
      code: "ER_UNKNOWN",
      status: statusCodes.INTERNAL_SERVER_ERROR
    }
  });
});
This post is licensed under CC BY 4.0 by the author.