Express.js에서 async/await를 사용하며 마주친 에러 핸들링 문제
문제 상황
Node 8이 출시되면서 async/await를 네이티브로 사용할 수 있게 됐다. 기존 Promise 체인을 async/await로 바꾸는 작업을 진행하던 중, Express 라우터에서 에러가 발생하면 서버가 응답 없이 멈춰버리는 현상을 발견했다.
app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
});
위 코드에서 User.findById가 reject되면 에러가 catch되지 않아 unhandled promise rejection이 발생한다.
해결 방법
1. 매번 try-catch 사용
app.get('/users/:id', async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
res.json(user);
} catch (error) {
next(error);
}
});
가장 기본적인 방법이지만 모든 라우터마다 try-catch를 작성해야 해서 번거롭다.
2. 래퍼 함수 작성
const asyncHandler = fn => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
}));
실제로 이 방식을 팀에 제안해서 적용했다. express-async-handler 같은 npm 패키지도 있지만, 코드가 간단해서 직접 유틸로 만들어 사용 중이다.
결론
async/await 자체는 코드를 깔끔하게 만들어주지만, Express는 아직 Promise 기반 미들웨어를 완전히 지원하지 않는다. 래퍼 함수를 만들어 사용하는 것이 현재로선 가장 실용적인 방법이었다.