fetch와 axios 비교

fetch와 axios 비교

웹 개발에서 데이터를 비동기적으로 가져오는 것은 매우 일반적인 작업이다. 이를 위해 주로 사용되는 두 가지 도구가 있는데, 바로 fetchaxios이다. 참고로 이들은 구식 브라우저에서는 지원하지 않으므로 폴리필이 필요하다.


Fetch

 

정의 :

  • 웹 브라우저 내장 API로, 네트워크 요청을 비동기적으로 처리하기 위해 만들어졌다. 

const res = await fetch(url);

res.status;  // response 코드
res.headers;  // response 헤더

// response body
await res.json(); // JSON 문자열을 파싱해서 자바스크립트 객체로 변환함.
await res.text(); // 문자열을 그대로 가져옴.
  • res.json() : 바디의 JSON 문자열을 파싱해서 자바스크립트 객체로 변환

  • res.text() : 바디의 내용을 문자열로 그대로 가져옴.

    • 만약 body의 내용이 JSON이 아닌데 res.json으로 파싱하면 오류가 남.

 

fetch() 옵션

  • method (메소드)

    • GET, POST, PATCH, DELETE

    • 지정하지 않으면 기본 값이 GET

  • headers (헤더)

    • Content-Type

    • Authorization

  • body (바디)

    • 자바스크립트 객체는 그대로 전달할 수 없기 때문에 JSON 문자열로 바꿔줘야 함.

 

장점 :

  • 웹 표준:

    • Fetch는 웹 표준으로, 모든 최신 브라우저에서 기본적으로 지원된다.

      웹 표준 API로서의 Fetch는 setTimeout, console 등과 함께 자주 사용된다.

     

단점 :

  • 추가 구현 필요:

    • Fetch를 사용할 때는 axios와 비교하여 수동으로 구현해야 하는 기능들이 있다.

    • 예를 들어, 요청과 응답을 중간에 가로채어 처리하는 Interceptor 기능은 직접 작성해야 한다.

       

    // 요청을 보내기 전에 수행할 작업
    const requestInterceptor = (url, options) => {
      console.log('Request Interceptor:', url, options);
      // 예: 인증 토큰 추가
      const modifiedOptions = {
        ...options,
        headers: {
          ...options.headers,
          'Authorization': 'Bearer YOUR_TOKEN'
        }
      };
      return { url, options: modifiedOptions };
    };
    
    // 응답을 받은 후에 수행할 작업
    const responseInterceptor = async (response) => {
      console.log('Response Interceptor:', response);
      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(`Error: ${response.status} - ${errorData.message}`);
      }
      return response.json();
    };
    
    const fetchWithInterceptors = async (url, options) => {
      const { url: interceptedUrl, options: interceptedOptions } = requestInterceptor(url, options);
      try {
        const response = await fetch(interceptedUrl, interceptedOptions);
        return await responseInterceptor(response);
      } catch (error) {
        // 에러 처리
        console.error('Fetch Error:', error);
        throw error;
      }
    };
    
    // 사용 예시
    fetchWithInterceptors('https://api.example.com/data', {
      method: 'GET'
    })
      .then(data => console.log('Data:', data))
      .catch(error => console.error('Error:', error));
  • 응답값 파싱:

    • Fetch는 기본적으로 응답값을 자동으로 파싱하지 않는다.

    • 응답을 JSON 형식으로 변환하려면 res.json() 메서드를 호출해야 한다. 이는 코드 작성 시 추가 단계를 필요로 한다.

    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => console.log(data))
      .catch(error => console.error('Error:', error));
  • 에러 핸들링:

     

    • HTTP 오류 상태 코드(예: 404, 500)는 Fetch에서는 자동으로 에러로 처리되지 않는다.

    • Fetch API에서는 HTTP 상태 코드가 200-299 범위가 아니어도 네트워크 요청이 성공하면 Promise를 반환한다. 따라서 상태 코드에 따라 별도로 오류를 처리해야한다. 이를 위해 res.status를 사용하여 각 상태 코드에 대한 처리를 세분화할 수 있다.

    export async function getColorSurvey(id) {
      const res = await fetch(`https://www./${id}`);
    
      if (!res.ok) {
        throw new Error('데이터를 불러오는데 실패했습니다.');
      }
    
      const data = await res.json();
      return data;
    }
export async function getColorSurvey(id) {
  const res = await fetch(`https://www.example.com/${id}`);

  // 상태 코드에 따라 오류 메시지를 다르게 처리
  if (!res.ok) {
    if (res.status >= 400 && res.status < 500) {
      throw new Error('클라이언트 오류가 발생했습니다. 요청을 다시 확인하세요.');
    } else if (res.status >= 500) {
      throw new Error('서버 오류가 발생했습니다. 나중에 다시 시도하세요.');
    } else {
      throw new Error('알 수 없는 오류가 발생했습니다.');
    }
  }

  const data = await res.json();
  return data;
}

 


 

axios

 

정의 :

  • 브라우저와 Node.js 환경 모두에서 동작하는 HTTP 클라이언트 라이브러리

  • axios는 HTTP 메소드 이름과 동일한 메소드를 사용하고 리스폰스 바디를 data 프로퍼티로 접근할 수 있다.

     

     

    axios 옵션

    GET, DELETE Request

  • Request body가 필요 없기 때문에 옵션을 두 번째 아규먼트로 받는다.

     

    POST, PATCH, PUT

  • Request

    Request에 보낼 body 내용은 두 번째 아규먼트로 받고, 옵션을 세 번째 아규먼트로 받는다.

  • 별도의 파싱과정이 없이 JSON으로 변환된다.

     

    // Axios 모듈 가져오기
    import axios from 'axios';
    
    // GET 요청 (Request Body 없음)
    axios.get('https://api.example.com/data', {
        // 옵션
        params: {
            id: 123
        },
        headers: {
            'Authorization': 'Bearer token123'
        }
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });
    
    // DELETE 요청 (Request Body 없음)
    axios.delete('https://api.example.com/data/123', {
        // 옵션
        headers: {
            'Authorization': 'Bearer token123'
        }
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });
    // POST 요청 (Request Body 있음)
    axios.post('https://api.example.com/data', {
        name: 'John Doe',
        age: 30
      }, {
        // 옵션
        headers: {
            'Authorization': 'Bearer token123'
        }
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });
    
    // PATCH 요청 (Request Body 있음)
    axios.patch('https://api.example.com/data/123', {
        age: 31
      }, {
        // 옵션
        headers: {
            'Authorization': 'Bearer token123'
        }
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });
    
    // PUT 요청 (Request Body 있음)
    axios.put('https://api.example.com/data/123', {
        name: 'Jane Doe',
        age: 25
      }, {
        // 옵션
        headers: {
            'Authorization': 'Bearer token123'
        }
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });

     

    axios 인스턴스

  • 리퀘스트마다 공통되는 부분이 있으면 axios.create()으로 인스턴스를 생성한다.

  • 해당 인스턴스로 리퀘스트를 보내면 된다.

    const axios = require('axios');
    
    // Axios 인스턴스 생성
    const instance = axios.create({
      baseURL: 'https://api.example.com/', // 기본 URL 설정
      timeout: 5000, // 타임아웃 설정 (밀리초)
      headers: {
        'Authorization': 'Bearer token123' // 기본 헤더 설정
      }
    });
    // GET 요청 예제
    instance.get('/data')
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });
    
    // POST 요청 예제
    instance.post('/data', {
        name: 'John Doe',
        age: 30
      })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error('에러 발생:', error);
      });

    https://axios-http.com/docs/instance

     

     

    참고 :

  • Fetch() 함수는 원래 웹 브라우저에서만 사용할 수 있었으며, Node.js에서는 사용할 수 없었다.

  • 그러나 Node.js v17.5부터 실험적인 기능으로 Fetch가 도입되었고, 이에 따라 주의 메시지가 출력되었다.

  • 이후, Node.js v18.13부터는 이 기능이 안정화되어 더 이상 주의 메시지가 출력되지 않는다.

 

장점 :

  • 간편한 코드 작성 : 코드 작성이 간편하다.

  • 직관적인 문법 : 문법이 직관적이다.

  • 다양한 기능 : 인터셉터, 타임아웃, 요청 취소 등의 기능을 제공한다.

  • 에러 처리 용이 : catch 블록에서 에러 처리가 가능하다.

  • 자동 JSON 파싱 : 응답 데이터(res.data)는 자동으로 JSON으로 파싱된다.
    (텍스트로 파싱이 필요할 경우 res.text()를 사용하면 된다.)

axios.get('https://api.example.com/data')
  .then(response => {
    console.log(response.data); // JSON 데이터, response.json() 불필요
  })
  .catch(error => {
    console.error('Error:', error);
  });

단점 :

  • 번들 사이즈 증가 : axios는 많은 기능을 제공하지만 그만큼 번들 사이즈를 증가시킨다. 특히 번들 사이즈가 커지면 로딩 시간이 길어질 수 있다.

 

axios의 기능 3개 :

1) 인터셉터

axios의 인터셉터는 요청과 응답을 가로채고 수정할 수 있는 기능이다. 이를 통해 전역적으로 요청과 응답을 처리하거나, 특정 상황에 맞게 헤더를 추가하거나 변경할 수 있다. 예를 들어, 모든 요청에 인증 토큰을 추가하거나, 응답 데이터를 특정 형식으로 변환하는 등의 작업을 수행할 수 있다.

 

모든 요청에 대해 인증 토큰 추가하기

axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
}, error => {
  return Promise.reject(error);
});

 

응답에 대한 에러 처리하기

axios.interceptors.response.use(response => {
  // 응답이 성공인 경우
  return response;
}, error => {
  // 응답이 에러인 경우
  if (error.response.status === 401) {
    // 인증 오류 처리
  } else if (error.response.status === 404) {
    // 리소스를 찾을 수 없음 처리
  } else {
    // 기타 오류 처리
  }
  return Promise.reject(error);
});

 

요청 또는 응답에 대한 로깅

axios.interceptors.request.use(config => {
  console.log('요청 시작:', config);
  return config;
});

axios.interceptors.response.use(response => {
  console.log('응답 받음:', response);
  return response;
}, error => {
  console.error('에러 발생:', error);
  return Promise.reject(error);
});

 

2) 타임아웃

  • axios는 요청에 대한 응답을 기다리는 시간을 설정할 수 있는 타임아웃 기능을 제공한다.

  • 이를 사용하여 서버로의 요청에 대한 응답이 지연되는 경우, 일정 시간이 지난 후에 요청을 취소하고 에러를 발생시킬 수 있다.

axios.get('/api/data', { timeout: 5000 })
  .then(response => {
    // 성공적으로 데이터를 받았을 때의 처리
  })
  .catch(error => {
    // 타임아웃 또는 다른 에러 처리
  });

 

3) 요청 취소 기능

  • axios는 요청을 취소하는 기능을 제공하여, 요청이 보내진 후에도 요청을 중단시킬 수 있다.

  • 이는 사용자가 요청을 취소하고 다른 작업을 수행할 때 유용하다.

const source = axios.CancelToken.source();

axios.get('/api/data', {
  cancelToken: source.token
})
.then(response => {
  // 성공적으로 데이터를 받았을 때의 처리
})
.catch(error => {
  if (axios.isCancel(error)) {
    // 요청이 취소된 경우 처리
  } else {
    // 다른 에러 처리
  }
});

// 요청 취소
source.cancel('요청이 사용자에 의해 취소되었습니다.')

댓글을 작성해보세요.