평화롭던 어느 오후였습니다.
새 프로젝트를 시작하면서 API 통신 코드를 짜려는데... 문득 그런생각이 들었어요
음 평소에 쓰던 Fetch, Axios 가 뭐가 다르지?
순간 머리가 하얘졌습니다. axios.get() 은 손에 익었는데,
"그래서 Fetch랑 뭐가 다른데요?" 라고 물으면
"음... Axios는 설치해야 해" 수준밖에 못 대답할 것 같았거든요.
그래서 그냥 직접 뜯어봤습니다. 헷갈리는 부분 네 가지만 골라서요.
Fetch API는 브라우저에 기본으로 내장된 인터페이스입니다. 별도 설치 없이 fetch() 메서드 하나로 네트워크 요청을 날릴 수 있어요. 모던 브라우저라면 그냥 씁니다.
Axios는 서드파티 라이브러리예요. CDN이나 npm, yarn으로 직접 설치해줘야 합니다.
npm install axios
# 또는
yarn add axios
그리고 둘 다 promise 기반의 HTTP 클라이언트라는 건 같아요. 이 공통점을 먼저 기억해두면 뒤가 훨씬 편합니다..!
.then() 이 몇 개야?Fetch
const url = "https://jsonplaceholder.typicode.com/todos";
fetch(url)
.then((response) => response.json())
.then(console.log);
Fetch는 응답이 와도 "나 왔어!" 라고만 합니다. JSON으로 바꿔주지는 않아요. response.json()을 직접 호출해야 하는데, 이것 자체가 promise를 반환하기 때문에 .then()이 두 번 필요합니다. 처음엔 이게 왜 두 개지? 했는데... 이런 이유였군요.
Axios
const url = "https://jsonplaceholder.typicode.com/todos";
axios.get(url).then((response) => console.log(response.data));
Axios는 기본적으로 JSON 형태로 응답 데이터를 콜백해줍니다. response.data에서 바로 꺼내 쓰면 돼요. .then() 하나로 끝납니다.
필요하다면 responseType 을 재정의할 수도 있어요.
axios.get(url, {
responseType: "json", // options: 'arraybuffer', 'document', 'blob', 'text', 'stream'
});
친절한 녀석..!
POST 요청 보낼 때 차이가 확 납니다.
Fetch
const url = "https://example.com";
const todo = {
title: "A new todo",
completed: false,
};
fetch(url, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(todo),
})
.then((response) => response.json())
.then((data) => console.log(data));
Fetch는 body에 데이터를 보내려면 JSON.stringify()로 직렬화하고, Content-Type도 직접 application/json으로 설정해줘야 합니다. 안 챙기면 서버가 못 알아들어요.
Axios
const url = "https://example.com";
const todo = {
title: "A new todo",
completed: false,
};
axios
.post(url, {
headers: {
"Content-Type": "application/json",
},
data: todo,
})
.then(console.log);
Axios는 데이터를 JSON 문자열로 알아서 직렬화해주고, Content-Type도 기본값이 application/json입니다. 사실상 헤더도 생략 가능해요.
Fetch: "넌 직접 챙겨."
Axios: "내가 다 해줄게~"
성격 차이가 느껴집니다 ㅋㅋㅋ.
이 부분이 개인적으로 제일 충격이었습니다.
Fetch
const url = "https://example.com";
fetch(url)
.then((response) => {
// response 의 ok 값으로 예외처리
// 해당 예외처리에서 걸리면 에러를 발생시키고 catch 영역으로 넘어가게 만든다.
if (!response.ok) {
throw new Error(
`This is an HTTP error: The status is ${response.status}`
);
}
return response.json();
})
.then(console.log)
.catch((err) => {
console.log(err.message);
});
Fetch는 404나 500 같은 HTTP 에러가 와도 promise를 reject하지 않습니다. 네트워크 자체에 문제가 생겼을 때만 reject해요.
그러니까 서버가 "404야, 없는 페이지야" 라고 답장을 보내도, Fetch는 "응답 왔어~" 라며 .then()으로 넘겨버립니다. 아무것도 모르는 척하고요. 그래서 위처럼 response.ok를 수동으로 체크해서 직접 에러를 던져줘야 합니다. 얄미웠다 ㅋㅋ
Axios
const url = "https://example.com";
axios
.get(url)
.then((response) => console.log(response.data))
.catch((err) => {
// 에러 처리
if (err.response) {
// 요청이 이루어졌고 서버가 응답했을 경우
const { status, config } = err.response;
if (status === 404) {
console.log(`${config.url} not found`);
}
if (status === 500) {
console.log("Server error");
}
} else if (err.request) {
// 요청이 이루어졌으나 서버에서 응답이 없었을 경우
console.log("Error", err.message);
} else {
// 그 외 다른 에러
console.log("Error", err.message);
}
});
// 요청 또는 응답 속성이 모두 없는 경우는 네트워크 요청을 설정하는 동안 오류가 발생한 경우입니다.
Axios의 promise는 상태 코드가 2XX 범위를 벗어나면 reject합니다. 서버가 에러를 내려보내면 바로 .catch()로 떨어지는 거예요. 에러 객체에 response나 request 프로퍼티가 있는지 확인하는 것만으로 에러 원인을 세분화해서 처리할 수 있습니다.
훨씬 직관적입니다..! Fetch의 조용한 묵인을 경험하고 나면 더 그렇게 느껴져요.
Axios
const url = "https://jsonplaceholder.typicode.com/todos";
axios
.get(url, {
timeout: 4000, // 기본 설정은 '0'입니다 (타임아웃 없음)
})
.then((response) => console.log(response.data))
.catch((err) => {
console.log(err.message);
});
Axios는 설정 객체에 timeout 속성 하나만 추가하면 됩니다. 위 코드는 요청이 4초 이상 걸리면 끊고 .catch()로 넘어가도록 한 거예요. 단순합니다.
Fetch
const url = "https://jsonplaceholder.typicode.com/todos";
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 4000);
fetch(url, {
signal: signal,
})
.then((response) => response.json())
.then(console.log)
.catch((err) => {
console.error(err.message);
});
Fetch에서 타임아웃을 구현하려면 AbortController 인터페이스를 꺼내야 합니다. controller 객체를 만들고, signal을 꺼내서 fetch()에 넘겨준 뒤, setTimeout으로 4초 후에 controller.abort()를 호출하는 방식이에요. abort()가 호출되면 연결된 fetch 요청이 종료됩니다.
코드 양이 확 늘어납니다. 기능은 동일한데 말이죠. ㅎㅎ
둘 다 비동기라서 체감 차이가 크진 않습니다. 굳이 따지자면 Fetch가 조금 더 빠르긴 해요. 브라우저 내장이니까 외부 라이브러리 로드 비용 자체가 없거든요.
그런데 솔직히 이 차이로 기술 선택을 바꿀 이유는 없을 것 같습니다.
| Fetch | Axios | |
|---|---|---|
| 설치 | 불필요 (내장) | 필요 (npm/yarn/CDN) |
| JSON 처리 | .json() 수동 변환 | 자동 (response.data) |
| 직렬화/헤더 | 직접 설정 | 자동 |
| HTTP 에러 reject | ❌ (수동 처리 필요) | ✅ (2XX 외 자동 reject) |
| 타임아웃 | AbortController 필요 | timeout 옵션 하나로 |
| 성능 | 약간 빠름 | 약간 느림 |
결국 Fetch는 "기본기에 충실하지만 손이 많이 가는 친구"이고, Axios는 "편의 기능을 잔뜩 챙겨온 친구"입니다.
작은 프로젝트나 외부 의존성을 줄이고 싶을 때는 Fetch, 예외처리나 타임아웃 같은 공통 처리를 깔끔하게 가져가고 싶을 때는 Axios가 더 잘 맞는 것 같습니다.
혹시 저처럼 "그래서 뭐가 다른 거죠?" 하는 분이 계셨다면 조금이나마 도움이 됐으면 좋겠어요. 저도 정리하면서 꽤 많이 배웠습니다..! ㅎㅎ
다음 삽질에서 또 만나요~