Node.js 18의 Fetch API 도입과 HTTP 클라이언트 선택 고민
배경
Node.js 18이 LTS로 승격되면서 프로젝트 업그레이드를 검토하던 중, 가장 눈에 띈 것은 Fetch API의 기본 탑재였다. 그동안 node-fetch나 axios를 써왔는데, 브라우저와 동일한 API를 Node.js에서도 쓸 수 있다는 점이 매력적이었다.
기존 HTTP 클라이언트 현황
우리 프로젝트에서는 axios를 주로 사용해왔다.
const axios = require('axios');
const response = await axios.get('https://api.example.com/users', {
headers: { 'Authorization': `Bearer ${token}` },
timeout: 5000
});
axios의 장점은 명확했다. 인터셉터로 에러 핸들링을 중앙화할 수 있고, timeout 설정이 간단하며, JSON 자동 파싱이 편했다.
Native Fetch 테스트
Node.js 18의 fetch를 테스트해봤다.
const response = await fetch('https://api.example.com/users', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
문법은 깔끔했지만 몇 가지 아쉬운 점이 있었다.
- Timeout 미지원: AbortController를 수동으로 구현해야 함
- 인터셉터 없음: 공통 에러 처리 로직을 별도로 구성해야 함
- HTTP 에러 처리: 4xx, 5xx도 reject되지 않아 수동 체크 필요
실제 적용 결정
결론적으로 기존 API 서버 코드는 axios를 유지하기로 했다. 다만 새로운 유틸리티 스크립트나 간단한 HTTP 요청에는 fetch를 사용하기로 했다.
// 간단한 헬스체크 스크립트
async function healthCheck() {
try {
const response = await fetch('https://api.example.com/health');
if (!response.ok) throw new Error(`Status: ${response.status}`);
return await response.json();
} catch (error) {
console.error('Health check failed:', error.message);
}
}
의존성 하나를 줄이는 것도 좋지만, 안정성과 생산성을 우선했다. fetch가 더 성숙해지고 타임아웃 등의 기능이 보강되면 그때 마이그레이션을 고려해볼 생각이다.
참고
- Node.js 18은 2022년 10월 LTS 예정
- fetch는 현재 experimental 플래그 없이 사용 가능
- 프로덕션 환경에서는 여전히 axios의 안정성을 신뢰