[JavaScript/node.js] Express.js Error Handling - 3

박상원·2022년 4월 24일
0

node

목록 보기
3/3
post-thumbnail

Node Express.JS 의 Router는 API 의 HTTP 요청을 처리할 수 있습니다. 라우팅을 통해서 우리는 기본적으로 비즈니스 로직을 실행하여 원하는 데이터 구조를 변경하여 애플리케이션레벨에 전달합니다.

이런 라우팅 과정에서 예외처리는 서버-클라이언트 구조에서 필수적인 통신 규칙이 될 수 있습니다. 어떤 데이터가 처리 됐는지 처리중에 어떤 오류를 리턴하여 클라이언트에서 반응을 해야할 지 모든 서버-클라이언트 구조의 일조으이 약속을 예외처리로 규정할 수 있습니다.

우리는 이전에 노드의 에러라는 객체와 이를 유용하게 사용하기 위해 커스텀을 하는 작업을 했습니다. 일종의 준비같은 작업으로 이번 에러 핸들링을 하기 위해서 라우터레벨에서 어떻게 에러를 핸들링하는지 알아야합니다.

node express.js 에서 라우터는 핸들러라는 미들웨어를 만들어 비즈니스 로직을 실행합니다. express 공식문서에서 라우터를 아래와 같이 정의했습니다.

app.METHOD(PATH, HANDLER)

method, path 는 생략하고 HANDLER 에 집중합니다! 핸들러는 라우트가 일치할때 실행되는 함수이자 콜백함수 이고 미들웨어라 합니다.

function (req, res, next) {
  next();
};

req와 res 는 미들웨어 함수에서 사용되는 HTTP 요청, 응답 객체 인수이고 next 는 다음 미들웨어의 콜백인수 입니다. next를 호출하면 그 다음 미들웨어가 호출됩니다. 일반적으로 라우터의 미들웨어 함수들은 배열이 올 수 도 있고, 함수인수의 연속일 수도 있습니다.

지금까지 본 미들웨어는 어플리케이션,라우터 레벨 미들웨어입니다.

이런 미들웨어들은 요청인자로부터 구현된 기능을 처리하고, 응답인자로부터 호출을 반환할 수 있습니다. 하지만 우리가 볼 것은 이것이 아닌 next(error) 로 던지는 오류처리 미들웨어입니다.

라우터 레벨에서는 next()를 호출할 때, 특정 인자를 넣어서 error를 던질 수 있습니다.

이제부터 라우터는 아래처럼 정의하여 대표적으로 예를 들 것입니다.

router.get('/path', function () {
   try {
      ...logic
   } catch (error) {
      next(error);
   }
})

이렇게 모든 라우터의 미들웨어에서 에러를 던지면 catch 가 그 에러를 받아 next(error) 하여 오류처리 미들웨어로 전달할 것입니다. 여기서 유념해야할 부분은 next()는 인자가 없으면 다음 콜백함수를 의미하지만 어떤 인자 값이 존재하는 경우 오류처리 핸들러로 인식하여 핸들링이 가능하게 됩니다.

그렇다면, 그 에러는 어디서 핸들링 될까요?

오류처리 미들웨어는 애플리케이션레벨 미들웨어와 조금 다른점이 있습니다.

// application level middleware
    app.use(function (req, res, next) {
        next();
    });
// error handler middleware
    app.use(function (err, req, res, next) {
        response_error(res, err);
    });

차이가 보이나요?

인자를 잘 살펴보시면 기본적인 req, res, next 가 있지만 오류처리 미들웨어는 err 이라는 인수를 하나 더 가지고 있습니다. 바로 이것이 오류처리 핸들러이고, 위에서 next(error)로 넘겼던 미들웨어가 이곳에서 발생합니다.

이제부터는 이 response_error 라는 함수내에서 에러를 핸들링 할 수 있게 됩니다.

여기서 부터는 응용력입니다. winston logger 를 사용하여 기록하여도 좋고 원하는 레벨의 error를 핸들링해도 좋습니다. 에러핸들러는 필수는 아니지만 없으면 서비스를 하기 어려울 정도로 중요한 미들웨어입니다.

저는 이 핸들러 안에서 error message나 code를 분기할 때 error 타입을 구분하여 사용하고 있습니다.

const get_message = (err) => {
    const { code: error_code } = err;
    let selected_message;
    if(err instanceof auth_error) {
        selected_message = get_auth_message(err);
    } else if (err instanceof custom_error) {
        ... etc
    } else {
        selected_message = get_service_message(err);
    }
    return selected_message;
}

이런식으로 이전 포스팅에서 구현했던 커스텀에러를 사용하여 환경에 맞는 에러핸들러를 구축할 수 있게됩니다.

세가지 순서로 알 수 있었던 에러핸들러 과정은 잘만들어두면 어디서든지 간단하게 에러를 던지고, 핸들링하여 생산성과 유지보수에 탁월한 효과를 볼 수 있습니다.

profile
BE Dev

0개의 댓글