Express.js에서 효율적인 API 에러 핸들링 방법: try-catch
없이 처리하기
API 서버를 구축할 때 에러 핸들링은 애플리케이션의 안정성과 유지보수성을 높이는 데 매우 중요한 요소입니다. 특히, Express.js에서는 에러 핸들링 미들웨어를 통해 발생한 에러를 일관성 있게 관리할 수 있어, 개별 컨트롤러에서 try-catch를 남발하는 상황을 피할 수 있습니다.
이번 글에서는 Express.js에서 try-catch 없이 API 에러를 처리하는 방법을 살펴보고, 통합 에러 핸들러를 활용하여 코드의 간결성을 유지하는 방법을 소개하겠습니다.
1. 에러 핸들링 미들웨어란?
에러 핸들링 미들웨어는 Express.js에서 발생한 모든 에러를 처리하는 중앙 관리 포인트입니다. 애플리케이션 내에서 에러가 발생했을 때 이를 처리하고, 적절한 응답을 클라이언트에 반환하는 역할을 합니다.
Express.js는 다음과 같은 기본 구조의 에러 핸들링 미들웨어를 제공합니다:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
이 미들웨어는 라우트에서 발생한 에러를 next(error)로 전달받아 처리하며, 모든 요청에 대한 에러를 중앙에서 관리할 수 있게 해줍니다.
2. try-catch 없이 에러를 처리하는 원리
일반적으로 비동기 코드를 작성할 때는 try-catch로 에러를 처리하게 됩니다. 하지만, Express.js에서는 에러 핸들링 미들웨어가 있으면 try-catch를 사용하지 않고, 조건에 따라 에러를 발생시키는 방식으로 에러를 관리할 수 있습니다.
자동 에러 처리 흐름
- 라우트 핸들러에서 에러가 발생하면,
throw new Error()
로 에러를 던집니다. - Express.js는 이 에러를 감지하고, 자동으로 에러 핸들링 미들웨어로 제어를 넘깁니다.
- 에러 핸들링 미들웨어에서 해당 에러를 처리하고, 클라이언트에게 적절한 에러 응답을 보냅니다.
3. 에러를 처리하는 방법: if문과 throw로 처리하기
컨트롤러에서 특정 조건을 검증할 때, try-catch 대신 if문과 throw를 사용하여 에러를 처리할 수 있습니다. 예를 들어, 필수 입력 값이 없을 때 에러를 던지는 방식으로 코드를 작성할 수 있습니다.
app.get('/api/data', async (req, res, next) => {
if (!req.body.id) {
throw new Error('ID is required'); // 에러 발생
}
const data = await someAsyncOperation();
res.json(data);
});
위 코드에서 req.body.id
가 없으면 try-catch 없이 바로 에러를 던집니다. Express.js는 이 에러를 자동으로 잡아 미들웨어로 전달하고, 미들웨어가 이를 처리해 클라이언트에 적절한 응답을 보냅니다.
4. 왜 try-catch를 남발하지 않는 것이 좋은가?
try-catch를 남발하게 되면 코드가 복잡해지고, 반복적인 에러 처리 로직이 코드 전체에 분산될 수 있습니다. 이런 방식은 유지보수가 어렵고, 특정 에러가 발생할 때 일관성 있는 처리가 어렵습니다.
통합 에러 핸들러를 사용하면 이러한 문제를 해결할 수 있습니다. 통합 에러 핸들러는 모든 에러를 중앙에서 관리하여 다음과 같은 장점을 제공합니다:
- 코드의 간결성: 컨트롤러에서 반복적인 try-catch 블록을 제거할 수 있습니다.
- 일관된 에러 처리: 에러를 하나의 미들웨어에서 처리하므로, 모든 에러에 대해 일관된 응답을 보낼 수 있습니다.
- 유지보수성 향상: 에러 처리 로직이 분산되지 않고, 중앙에서 관리되므로 유지보수가 훨씬 용이해집니다.
5. 에러 핸들러 미들웨어 구현하기
Express.js에서 통합 에러 핸들러를 구현하면, 모든 라우트에서 발생한 에러를 일괄적으로 처리할 수 있습니다. 아래와 같은 코드를 통해 통합 에러 핸들러를 구현할 수 있습니다:
app.use((err, req, res, next) => {
// 에러 로깅
console.error(err.message);
// 에러 응답
if (err.name === 'ValidationError') {
return res.status(400).json({ error: err.message });
}
// 일반적인 서버 에러
res.status(500).json({ error: 'Internal Server Error' });
});
이 코드에서는 에러 메시지를 로깅하고, 에러의 종류에 따라 다른 상태 코드를 반환하도록 처리합니다. 이를 통해 클라이언트는 에러 상황을 명확하게 인식할 수 있습니다.
이제 Express.js에서 통합 에러 핸들링을 활용해, 더 효율적인 API를 작성해보세요!