[번역] Axios vs Fetch | 입문자에게 좋은 것은?

ZenTechie·2023년 5월 6일
0

study

목록 보기
5/11
post-thumbnail

네트워크 요청이 필요한 어플리케이션을 제작할 때, Axios, Fetch 같은 HTTP client를 사용한다.

Axios와 Fetch 중 어느 것을 선택해서 사용해야 하는지 비교 해보도록 하자.

Fetch와 Axois의 개요

Fetch API는 네트워크 요청을 위해 fetch()라는 메소드를 제공하는 인터페이스이다.
모던 브라우저에 내장되어 있어서 설치가 따로 필요없다. 또한, node.js의 실험적 기능을 사용하여 이용할 수 있다.

Axios는 서드-파티 라이브러리로 CDN 또는 패키지 매니저(npm, yarn)를 통해 설치함으로서 사용할 수 있다. Axios는 브라우저 또는 node.js 환경에서 사용할 수 있다.

Fetch와 Axios는 모두 Promise 기반의 HTTP client이다.
우리가 네트워크 요청을 위해 이들을 사용하면, resolve 또는 reject할 수 있는 promise가 반환된다.

Axios 설치하기

Axios를 node.js 환경에서 사용한다면, 다음의 방법들로 설치를 해야한다.

  1. NPM을 사용하여 설치
npm install axios
  1. Yarn을 사용하여 설치
yarn add axios

그리고 현재 프로젝트에 다음과 같이 import한다.

import axios from "axios";

만약, 브라우저 내에서 Axios를 사용한다면, CDN을 사용할 수 있다.

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Fetch와 Axios의 기능 비교

문법

Fetch는 2개의 인자가 필요하다. 첫 번째 인자는 우리가 fetch하려는 리소스의 URL이다.
두 번째 인자는 Request의 설정 옵션을 포함하는데, 이는 필수로 사용하지 않아도 된다.

설정 옵션을 제외한다면, 기본적으로 다음과 같은 GET 요청을 보낸다.

fetch(url)

설정 옵션을 포함한다면, 다음과 같이 커스텀 세팅을 설정한다.

fetch(url, {
  method: 'GET', // 다른 옵션 : POST, PUT, DELETE 등
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({}),
})

Axios의 문법도 이와 비슷하지만, 다른 여러 방식으로 요청할 수 있다.

axios(url, {
  // 설정 옵션
})

HTTP 메소드를 추가해서 요청할 수도 있다.

axios.get(url, {
  // 설정 옵션
})

fetch와 마찬가지로, HTTP 메소드가 없다면 기본적으로 GET 요청을 보낸다.

axios(url)

이와 비슷하게, 2번째 인자에 커스텀 세팅을 설정할 수 있다.

axios(url, {
  method: 'get', // 다른 옵션 : post, put, delete 등
  header: {},
  data: {},
})

아래와 같은 방식으로도 요청이 가능하다.

axios({
  method: 'get',
  url: url,
  header: {},
  data: {},
})

자, 이제는 Axios와 fetch에서의 응답 처리 방법에 대해 알아보자.

JSON 데이터 처리

아래의 예시는, JSONPlaceholder라는 REST API의 투두 리스트의 아이템들을 가져오기 위해 GET 요청을 보낸다. 이를 통해 fetch와 Axios의 차이점을 살펴보자.

Fetch API를 사용하면, 다음과 같은 코드로 작성할 수 있다.

const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url)
  .then(response => response.json())
  .then(console.log);

콘솔에 출력되는 결과는 다음과 같다.

fetch().then() 메소드에 의해 처리되는 promise를 반환한다.
이 시점에서, 우리가 원하는 JSON 데이터가 아니기 때문에 .json() 메소드를 호출한다.
그러면 JSON 형태로 이행(resolve)된 다른 promise를 반환한다.
결과적으로, fetch 요청은 두 개의 .then() 호출을 포함한다.

그러나, 우리가 Axios를 사용한다면, 다음과 같은 코드로 작성할 수 있다.

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url)
.then(response => console.log(response.data));

Axios에서는 응답 데이터가 기본적으로 JSON 형태이다. 응답 데이터는 항상 응답 객체의 data 프로퍼티로 접근이 가능하다.

설정 옵션에서 responseType을 명시해서 JSON 데이터 타입을 재정의할 수도 있다.

axios.get(url, {
  responseType: 'json' // 옵션: 'arraybuffer', 'document', 'blob', 'text', 'stream'
})

자동 문자열화(Stringify)

JSONPlaceholder API를 사용해서 데이터를 보내보자.

먼저, 데이터를 JSON 문자열로 Serialize해야 한다. POST 메소드를 사용해서 API에 JavaScript 객체를 보낼 때, Axios는 자동적으로 데이터를 문자열화 해준다.

다음은 Axios를 사용하여 post 요청을 보내는 코드이다.

const url = "https://jsonplaceholder.typicode.com/todos";

const todo = {
  title: "A new todo",
  completed: false
} 

axios.post(url, {
  headers: {
    'Content-Type': 'application/json',
  },
  data: todo
})
.then(console.log);

우리가 Axios를 사용해서 post 요청을 보낼 때, 요청 본문으로 보내려고 하는 data 를 data 프로퍼티에 할당한다.
또한, 컨텐츠 유형 헤더를 설정할 수도 있다.
기본적으로 Axios는 Content-Typeapplication/json으로 설정한다.

자, 응답 객체를 살펴보자.

응답 데이터는 다음과 같이 response.data 에 위치해 있다.

.then(response => console.log(response.data));

만약 Fetch API를 사용한다면, JSON.stringify() 를 사용해서 직접 객체를 문자열화 하고 요청의 body(본문) 에 할당해야 한다.

const url = "https://jsonplaceholder.typicode.com/todos";

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))javascript

이때 반드시 명시적으로 Content-Typeapplication/json으로 설정해야 한다.

에러 처리(Error Handling)

fetch와 Axios 모두 이행(resolved)되거나 거절(rejected)되는 promise를 반환한다.
promise가 거절되었을 때, .catch()를 사용해서 에러를 처리할 수 있다.
우리가 어떻게 에러를 처리 하느냐에 따라서 axios는 fetch보다 코드가 간결해진다.

먼저 Axios를 살펴보자. .catch()를 사용한 전형적인 에러 처리는 다음과 같다.

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url)
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
});

Axios의 promise는 상태 코드가 2xx 범위를 넘어갈 때 거부(reject)할 것이다.
다음과 같이 에러 객체가 response또는 request 프로퍼티를 포함하는지를 확인 해보면서 더 많은 정보를 확인할 수 있다.

.catch((err) => {
  // handling error
  if (err.response) {
    // Request made and server responded

    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) {
    // Request made but no response from server
    console.log("Error", err.message);
  } else {
    // some other errors
    console.log("Error", err.message);
  }
});

에러 객체의 response 프로퍼티는, 클라이언트가 상태코드가 2xx 범위를 넘어가는 잘못된 응답을 받았음을 의미한다.
에러 객체의 request 프로퍼티는, 요청은 만들어졌으나 클라이언트가 응답을 전혀 받지 못했음을 의미한다.
이와 다르게, 만약 어떠한 요청이나 응답 프로퍼티가 없다면, 에러는 네트워크 요청을 설정하는데에서 발생한 것이다.

Fetch는 404 에러나 다른 HTTP 에러를 받았을 때 promise를 거부(reject)하지 않는다.
Fetch는 오직 네트워크가 실패했을 때만 promise를 거부(reject)한다.
그래서 우리는 .then을 사용해서 HTTP 에러를 직접 처리해줘야 한다.

다음의 코드를 살펴보자.

const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url) 
  .then((response) => {
    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);
});

응답 블록에서, response.ok 가 false인지 확인하고 있다. 그리고 .catch 블록에서 처리되는 커스텀 에러를 throw한다.

다음과 같이 응답 객체에서 사용할 수 있는 메소드를 살펴볼 수 있다.

.then(console.log)

위의 스크린샷은 성공적인 fetch를 나타낸다.
만약, okstatus 프로퍼티는 false404가 되도록 만드는, 잘못된 URL Endpoint를 요청할 경우에는 에러를 발생시키고 .catch()를 사용해서 커스텀 에러 메시지를 화면에 띄울 것이다.

응답 시간초과 / 요청 취소

HTTP 클라이언트가 HTTP 요청의 응답 시간초과를 어떻게 처리하는지 살펴보자.
Axios에서는, 설정 객체에 timeout 프로퍼티를 추가해서 요청이 종료되기 까지의 시간을 ms 단위로 할당한다.

다음의 코드를 살펴보면, 요청이 4초를 넘어간다면 종료하고 콘솔에 에러의 로그를 출력한다.

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url, {
  timeout: 4000, // default is `0` (no timeout)
})
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

Fetch를 사용해서 요청을 취소하려면, AbortController interface를 사용하면 된다.

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);
});

controller 객체를 생성하면, signal 객체와 abort() 메소드를 접근할 수 있게 된다. 그리고 설정 옵션을 통해 fetch()signal 객체를 전달한다.
위 과정을 통해서, abort 메소드가 호출될 때 마다 fetch 요청은 종료된다.
코드에서 볼 수 있듯이, setTimeout 함수를 사용해서 서버가 4초 내에 응답하지 않는다면 동작을 종료시킬 수 있다.

성능

Fetch와 Axios는 모두 Promise를 기반으로 한다. 그래서 어떠한 성능적 이슈를 발생시키지는 않을 것이다. 궁긍하다면, measurethat.net에서 성능을 측정할 수는 있다.

측정이 끝나면, 다음과 같은 결과를 얻을 수 있다.

그래프는 다음과 같다.

그림에서 볼 수 있듯이, 네이티브인 Fetch가 Axios보다 살짝 더 빠르다.
하지만, 두 클라이언트 모두 비동기 방식이라는 점에서 유의미하지는 않다.

브라우저 호환성

Axios와 Fetch는 모두 모던 브라우저에서 광범위하게 지원된다.
IE 11같은 오래된 환경에서는 ES6 Promises를 지원하지 않아서 polyfill을 사용해야 한다.
Fetch도 마찬가지로 오래된 브라우저에서 구현을 지원하기 위해 또 다른 polyfill을 추가해야 한다.

결론

이번 글에서, 실제 세계에서의 시나리오를 토대로 Fetch와 Axios를 비교해보았다.
결론적으로, Fetch와 Axios 중 무엇을 선택해서 사용하느냐는 개인적인 선호도와 사용 편의성에 달려있다.

원문 출처: https://www.meticulous.ai/blog/fetch-vs-axios

profile
데브코스 진행 중.. ~ 2024.03

0개의 댓글