Node.js 18의 Native Fetch API 도입 후기

배경

그동안 Node.js에서 HTTP 요청을 보낼 때 axios나 node-fetch 같은 외부 라이브러리에 의존해야 했다. 브라우저에서는 fetch를 쓰다가 서버사이드로 넘어오면 다른 라이브러리를 써야 하는 불편함이 있었는데, Node.js 18부터 fetch가 실험적 기능으로 추가되었다.

기존 방식과 비교

기존에는 이렇게 작성했다:

const axios = require('axios');

const response = await axios.get('https://api.example.com/data');
const data = response.data;

Node.js 18부터는 별도 설치 없이 가능하다:

const response = await fetch('https://api.example.com/data');
const data = await response.json();

실제 적용 케이스

사내 API Gateway 서비스를 리팩토링하면서 적용했다. 기존에 axios로 작성된 200여 개의 엔드포인트 호출 로직을 fetch로 전환했다.

// AS-IS
try {
  const res = await axios.post(url, payload, { headers });
  return res.data;
} catch (error) {
  if (error.response) {
    throw new ApiError(error.response.status);
  }
  throw error;
}

// TO-BE
const res = await fetch(url, {
  method: 'POST',
  headers,
  body: JSON.stringify(payload)
});

if (!res.ok) {
  throw new ApiError(res.status);
}

return await res.json();

주의사항

  1. 에러 처리 방식이 다르다 - fetch는 네트워크 오류가 아니면 reject하지 않는다. response.ok로 명시적 체크가 필요하다.
  2. 실험적 기능 - --experimental-fetch 플래그 없이 쓸 수 있지만 프로덕션에서는 신중해야 한다.
  3. 타임아웃 - axios처럼 기본 타임아웃이 없다. AbortController를 직접 구현해야 한다.

결론

번들 사이즈가 약 800KB 줄었고, 브라우저/서버 코드 통일로 개발 경험이 개선되었다. 다만 아직 실험적 기능이라 당장 모든 프로젝트에 적용하긴 이르다. Node.js 18 LTS가 안정화되면 점진적으로 마이그레이션할 계획이다.