Express.js에서의 에러 핸들링: 세 가지 접근 방식
Express.js 애플리케이션에서 에러를 효과적으로 처리하는 것은 매우 중요합니다. 여기서는 세 가지 주요 에러 핸들링 접근 방식을 살펴보고, 각각의 장단점을 분석해 보겠습니다.
1. Promise 기반 asyncHandler
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
장점:
- 동기 및 비동기 에러를 모두 캐치할 수 있습니다.
- 모든 종류의 함수(동기/비동기)를 안전하게 처리할 수 있습니다.
- Promise로 래핑되어 일관된 에러 처리가 가능합니다.
동작 원리:
- 함수를 Promise로 감싸 실행합니다.
- 에러 발생 시 catch로 잡아 next()를 통해 에러 핸들러로 전달합니다.
2. async/await 기반 asyncHandler
const asyncHandler = (fn) => async (req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
장점:
- 코드가 직관적이고 읽기 쉽습니다.
- 디버깅이 용이합니다.
- 동기 및 비동기 에러를 모두 처리할 수 있습니다.
제한사항:
- async 함수로 래핑되므로, 비동기 컨텍스트에서 최적화되어 있습니다.
3. try-catch 기반 asyncHandler
const asyncHandler = (fn) => (req, res, next) => {
try {
const result = fn(req, res, next);
if (result instanceof Promise) {
result.catch(next);
}
} catch (error) {
next(error);
}
};
장점:
- 구조가 단순하고 가벼움
- 동기 코드에 적합함
제한사항:
- 비동기 에러 처리를 위해서는 추가적인 로직이 필요합니다.
실제 사용 사례 분석
MongoDB 쿼리 처리
app.get(
"/api/contents",
asyncHandler(async (req, res) => {
const contents = await Content.find();
res.json(contents);
})
);
- Promise 기반: 모든 종류의 에러를 안전하게 처리합니다.
- async/await 기반: 동기 및 비동기 에러를 모두 처리합니다.
- try-catch 기반: 즉시 발생하는 에러는 처리하지만, Promise rejection은 별도 처리가 필요합니다.
동기 유효성 검사
const validateTitle = (title) => {
if (!title) throw new Error('제목 필수');
return title;
}
app.post("/api/contents", asyncHandler(async (req, res) => {
const title = validateTitle(req.body.title);
// ... 나머지 로직
}));
모든 접근 방식에서 동기 에러를 잘 처리할 수 있습니다.
디버깅과 로깅
로깅 전략
// 요청 로깅
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
// 응답 로깅
console.log('Response:', result);
// 에러 로깅
console.error('Error:', error);
Mongoose 디버그 모드
mongoose.set('debug', true);
결론
각 접근 방식은 고유한 장단점을 가지고 있습니다:
- Promise 기반 패턴: 가장 범용적이고 안전하지만, 복잡할 수 있습니다.
- async/await 패턴: 가독성이 좋고 직관적이며, 대부분의 상황에서 효과적입니다.
- try-catch 패턴: 단순하고 가벼우나, 비동기 에러 처리에 추가 작업이 필요합니다.
상황과 프로젝트의 요구사항에 따라 적절한 패턴을 선택하는 것이 중요합니다. 대부분의 경우 async/await 패턴이 좋은 균형을 제공하지만, 특수한 요구사항이 있다면 다른 패턴을 고려해볼 수 있습니다.