Axios - Front용 한방 정리

장현욱(Artlogy)·2022년 9월 6일
1

REST API

목록 보기
2/2
post-thumbnail

왜 Axios인가?

서버와 통신하는 라이브러리 3대장으로 AJAX,FETCH,AXIOS가 있지만,
현업에선 AXIOS를 압도적으로 많이쓴다. 왜 그런지 부터 알고가자.

AJAXJquery기반이기 때문에 jquery를 사용해야 호완성이 보장되고 Promise기반이 아닌 callback기반이기 때문에 Promise기반을 주로 쓰는 요즘 추세와 맞지않는다.

Fetch는 js가 ES6버전으로 업글되면서 들어온 내장 라이브러리인데 지원하지않는 브라우저가 존재하고 네트워크 에러발생시 response timeout기능이 없어 따로 만들어주거나 하염없이 기다려야한다.
또한 json으로 데이터를 직렬화해주는 과정이 필요하기 때문에 주류로 쓰기엔 불편한점이 많다.

axios는 위에 설명한 애들이 가지지 못한 장점과 더불어 확장된 기능 또한 사용이 가능하기때문에 현업에선 axios를 주류로 많이 쓰는 추세이다. 유일한 단점은 외부 라이브러리라 설치해야된다는 점 뿐인거같다.

Axios 맛보기

모든 과정은 Axios 공식 사이트를 기반으로 설명하겠다.

또한 axios는 프론트단에서 주로 사용하기에 React + js기반으로 설명하겠다.

Axios 설치

$ npm install axios
$ yarn add axios

Axios + REST API 통신

Get 요청

import axios from "axios"

const restApi = axios.default;

//GET QUERY 요청
restApi.get('/user?ID=1234')
	.then((response)=>{
		//성공 핸들링
  		console.log(reponse);
	})
	.catch((error)=>{
		//에러 핸들링
  		console.log(error);
	})
	.then(()=>{
		//항상 실행되는 영역 (final)
	});

//GET PARAMS 요청
restApi.get('/user',{
  	params:{
  		ID:1234
		}
     })
	.then((response)=>{
		//성공 핸들링
  		console.log(reponse);
	})
	.catch((error)=>{
		//에러 핸들링
  		console.log(error);
	})
	.then(()=>{
		//항상 실행되는 영역 (final)
	});

//여러개의 요청 처리 ( restApi.spread()도 존재한다. )
restApi.all([restApi.get('/userID=1234'),
             restApi.get('/user/12345/permissions')])
	.then((results)=>{
  		//성공 핸들링
		const acct = results[0];
  		const perm = results[1];
	})
	.catch((errors)=>{
		//에러 핸들링
  		const acctError = errors[0];
  		const permError = errors[1];
	});

Post 요청

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
  	//성공 핸들링
    console.log(response);
  })
  .catch(function (error) {
  	//에러 핸들링
    console.log(error);
  });

put, patch, delete는 post의 확장문이기 때문에 따로 설명하진 않겠다.
(axios에 내장함수로 있다.)

Axios Config

import axios from "axios";

axios.create({
    // `url`은 요청에 사용될 서버 URL입니다.
    url: "/user",

    // `method`는 요청을 생성할때 사용되는 메소드입니다.
    method: "get", // 기본값

    // `url`이 절대값이 아닌 경우 `baseURL`은 URL 앞에 붙습니다.
    // 상대적인 URL을 인스턴스 메서드에 전달하려면 `baseURL`을 설정하는 것은 편리합니다.
    baseURL: "https://some-domain.com/api",

    // `transformRequest`는 요청 데이터를 서버로 전송하기 전에 변경할 수 있게 해줍니다.
    // 이것은 'PUT', 'POST', 'PATCH', 'DELETE' 메소드에서만 적용됩니다.
    // 마지막 함수는 Buffer, ArrayBuffer, FormData 또는 Stream의 인스턴스 또는 문자열을 반환해야 합니다.
    // 헤더 객체를 수정할 수 있습니다.
    transformRequest: [
        function (data, headers) {
            // 데이터를 변환하려는 작업 수행

            return data;
        },
    ],

    // `transformResponse`는 응답 데이터가 then/catch로 전달되기 전에 변경할 수 있게 해줍니다.
    transformResponse: [
        function (data) {
            // 데이터를 변환하려는 작업 수행

            return data;
        },
    ],

    // `headers`는 사용자 지정 헤더입니다.
    headers: { "X-Requested-With": "XMLHttpRequest" },

    // `params`은 요청과 함께 전송되는 URL 파라미터입니다.
    // 반드시 일반 객체나 URLSearchParams 객체여야 합니다.
    // 참고: null이나 undefined는 URL에 렌더링되지 않습니다.
    params: {
        ID: 12345,
    },

    // `paramsSerializer`는 `params`의 시리얼라이즈를 담당하는 옵션 함수입니다.
    // (예: https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
    paramsSerializer: function (params) {
        return Qs.stringify(params, { arrayFormat: "brackets" });
    },

    // `data`는 요청 바디로 전송될 데이터입니다.
    // 'PUT', 'POST', 'PATCH', 'DELETE' 메소드에서만 적용 가능합니다.
    // `transformRequest`가 설정되지 않은 경우 다음 타입 중 하나여야 합니다.
    // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
    // - 브라우저 전용: FormData, File, Blob
    // - Node 전용: Stream, Buffer
    data: {
        firstName: "Fred",
    },

    // 바디로 전송하는 데이터의 대안 문법
    // POST 메소드
    // 키가 아닌 값만 전송됩니다.
    data: "Country=Brasil&City=Belo Horizonte",

    // `timeout`은 요청이 시간 초과되기 전의 시간(밀리초)을 지정합니다.
    // 요청이 `timeout`보다 오래 걸리면 요청이 중단됩니다.
    timeout: 1000, // 기본값은 `0` (타임아웃 없음)

    // `withCredentials`은 자격 증명을 사용하여 사이트 간 액세스 제어 요청을 해야 하는지 여부를 나타냅니다.
    withCredentials: false, // 기본값

    // `adapter`'은 커스텀 핸들링 요청을 처리할 수 있어 테스트가 쉬워집니다.
    // 유효한 Promise 응답을 반환해야 합니다. (lib/adapters/README.md 참고)
    adapter: function (config) {
        /* ... */
    },

    // `auth`는 HTTP Basic 인증이 사용되며, 자격 증명을 제공합니다.
    // `auth`를 사용하면, `Authorization` 헤더가 설정되어 `headers`를 사용하여 설정한 기존의 `Authorization` 사용자 지정 헤더를 덮어씁니다.
    // 이 파라미터를 통해 HTTP Basic 인증만 구성할 수 있음을 참고하세요.
    // Bearer 토큰 등의 경우 `Authorization` 사용자 지정 헤더를 대신 사용합니다.
    auth: {
        username: "janedoe",
        password: "s00pers3cret",
    },

    // `responseType`은 서버에서 받는 데이터의 타입입니다.
    // 옵션: 'arraybuffer', 'document', 'json', 'text', 'stream'
    // 브라우저 전용: 'blob'
    responseType: "json", // 기본값

    // `responseEncoding`은 응답 디코딩에 사용할 인코딩입니다.
    // Node.js 전용
    // 참고: 클라이언트 사이드 요청 또는 `responseType`이 'stream'이면 무시합니다.
    responseEncoding: "utf8", // 기본값

    // `xsrfCookieName`은 xsrf 토큰 값으로 사용할 쿠키의 이름입니다.
    xsrfCookieName: "XSRF-TOKEN", // 기본값

    // `xsrfHeaderName`은 xsrf 토큰 값을 운반하는 HTTP 헤더의 이름입니다.
    xsrfHeaderName: "X-XSRF-TOKEN", // 기본값

    // `onUploadProgress`는 업로드 진행 이벤트를 처리합니다.
    // 브라우저 전용
    onUploadProgress: function (progressEvent) {
        // 업로드 진행 이벤트 작업 수행
    },

    // `onDownloadProgress`는 다운로드로드 진행 이벤트를 처리합니다.
    // 브라우저 전용
    onDownloadProgress: function (progressEvent) {
        // 다운로드 진행 이벤트 작업 수행
    },

    // `maxContentLength`는 node.js에서 허용되는 http 응답 콘텐츠의 최대 크기를 바이트 단위로 정의합니다.
    maxContentLength: 2000,

    // `maxBodyLength`는 허용되는 http 요청 콘텐츠의 최대 크기를 바이트 단위로 정의합니다.
    // Node.js 전용
    maxBodyLength: 2000,

    // `validateStatus`는 지정된 HTTP 응답 상태 코드에 대한 Promise를 이행할지 또는 거부할지 여부를 정의합니다.
    // 만약 `validateStatus`가 true를 반환하면(또는 'null' 또는 'undefined'으로 설정) Promise는 이행됩니다.
    // 그렇지 않으면, 그 Promise는 거부될 것이다.
    validateStatus: function (status) {
        return status >= 200 && status < 300; // 기본값
    },

    // `maxRedirects`는 node.js에서 리디렉션 최대값을 정의합니다.
    // 0으로 설정하면 리디렉션되지 않습니다.
    maxRedirects: 5, // 기본값

    // `socketPath`는 node.js에서 사용될 UNIX 소켓을 정의합니다.
    // 예: '/var/run/docker.sock' 도커 데몬에 요청을 보냅니다.
    // 오직 `socketPath` 또는 `proxy`만 지정할 수 있습니다.
    // 둘 다 지정되면 `socketPath`가 사용됩니다.
    socketPath: null, // 기본값

    // `httpAgent`와 `httpsAgent`는 각각 node.js에서 http 및 https 요청을 수행할 때 사용할 사용자 지정 에이전트를 정의합니다.
    // 이렇게 하면 기본적으로 활성화되지 않은 `keepAlive`와 같은 옵션을 추가할 수 있습니다.
    httpAgent: new http.Agent({ keepAlive: true }),
    httpsAgent: new https.Agent({ keepAlive: true }),

    // `proxy`는 프록시 서버의 호스트이름, 포트, 프로토콜을 정의합니다.
    // 기존의 `http_proxy`와 `https_proxy` 환경 변수를 사용하여
    // 프록시를 정의할 수도 있습니다.
    // 프록시 구성에 환경 변수를 사용하는 경우, 'no_proxy' 환경 변수를
    // 쉼표로 구분된 프록시가 되지 않는 도메인 목록으로 정의할 수도 있습니다.
    // `false`를 사용하면 프록시를 사용하지 않고, 환경 변수를 무시합니다.
    // `auth`는 프록시에 연결하는데 HTTP Basic auth를 사용해야 함을 나타내며,
    // 자격 증명을 제공합니다. 그러면 `Proxy-Authorization` 헤더가 설정되고,
    // `headers`를 사용하여 기존의 `Proxy-Authorization` 사용자 지정 해더를 덮어씁니다.
    // 만약 프록시 서버가 HTTPS를 사용한다면, 프로토콜을 반드시 `https`로 설정해야 합니다.
    proxy: {
        protocol: "https",
        host: "127.0.0.1",
        port: 9000,
        auth: {
            username: "mikeymike",
            password: "rapunz3l",
        },
    },

    // `cancelToken`은 요청을 취소하는 데 사용할 수 있는 취소 토큰을 지정합니다.
    // (자세한 내용은 요청 취소 섹션 참조)
    cancelToken: new CancelToken(function (cancel) {}),

    // `decompress`는 응답 바디의 자동 압축 해제 여부를 나타냅니다.
    //  `true`로 설정하면, 압축 해제된 모든 응답에서 'content-encoding' 헤더도 제거됩니다.
    // Node.js 전용 (XHR은 압축 해제할 수 없습니다)
    decompress: true, // 기본값
});

많은 설정이 있는데 꼭 알아야 하는 것만 설명하겠다.

url : 말그대로 통신 할 url을 뜻한다. (config에 이걸 미리 설정하는일은 극히 드물다)

baseUrl : 기본이되는 url을 뜻한다. 설정하면 baseUrl + url형태로 스트링이 join된다.
주로 api 서버 주소를 설정할때 쓴다.

transformRequest: 요청을 보내기 직전 실행 할 기능을 뜻한다. (interceptor)

transformResponse: 응답을 받기 직전 실행 할 기능을 뜻한다. (interceptor)

headers: 사용자 지정헤더이다. 기본 헤더 스키마에 추가된다고 생각하면된다.

params: get요청중 params데이터가 필요할때 사용한다.

paramsSerializer: params 데이터를 서버쪽 dto validate에 맞게 직렬화 할때 사용한다.
(params 전용 interceptor라고 봐도 무방하다.)

data: 요청시 body 데이터이다. post요청 및 post확장 요청인 patch, delete, put에 주로쓰인다.

timeout: 서버와 통신시 최대 응답 대기 시간이다. 단위는 ms이다. 1000 = 1초
최대 응답 대기 시간이 넘어가면 axios는 error를 반환한다.

withCredentials: cors정책과 연관된 설정이다.
간단히 말하면 back serv가 front serv에 있는 쿠키값을 공유하고 싶다면 true, 아닐경우 false를 하면된다. 쿠키는 Request headers안 Cookies에 존재한다.

auth : 서버와 권한을 통신할때 주로 쓰인다. 설정시 headers에 Authorization의 값이 된다.
이곳에 토큰을 담아도되고 로그인 정보를 담는 식으로 많이 쓴다.

responseType : 서버에서 받는 데이터의 타입이다.

onUploadProgress : 서버에 업로드 할 때 실행되는 이벤트이다.
주로 업로드 progress bar를 만들때 많이 사용한다.

onDownloadProgress : 서버에서 다운로드 받을때 실행되는 이벤트이다.
주로 다운로드 progress bar를 만들때 많이 사용한다.

나머지는 딥한 내용이라 넘어가겠다

응답 스키마

{
  // `data`는 서버가 제공하는 응답입니다.
  data: {},

  // `status`는 HTTP 상태 코드입니다.
  status: 200,

  // `statusText`는 HTTP 상태 메시지입니다.
  statusText: 'OK',

  // `headers`는 HTTP 헤더입니다.
  // 모든 헤더 이름은 소문자이며, 괄호 표기법을 사용하여 접근할 수 있습니다.
  // 예시: `response.headers['content-type']`
  headers: {},

  // `config`는 요청을 위해 `Axios`가 제공하는 구성입니다.
  config: {},

  // `request`는 이번 응답으로 생성된 요청입니다.
  // 이것은 node.js에서 마지막 ClientRequest 인스턴스 입니다.
  // 브라우저에서는 XMLHttpRequest입니다.
  request: {}
}

이 중 중요한건 status라고 필자는 생각한다.
응답코드만 잘 알고있어도 서버 잘못인지 프론트 잘못인지 어디서 버그가 생겼는지 파악하기 쉽다.
다 외울 필요는 없고 앞자리가 의미하는 바와 500,404,200,403 정도만 확실히 기억해두면 좋다.

인터셉터

then 또는 catch로 처리되기 전에 요청과 응답을 가로챌수 있는 기능이다.

// 요청 인터셉터 추가하기
axios.interceptors.request.use(function (config) {
    // 요청이 전달되기 전에 작업 수행
    return config;
  }, function (error) {
    // 요청 오류가 있는 작업 수행
    return Promise.reject(error);
  });

// 응답 인터셉터 추가하기
axios.interceptors.response.use(function (response) {
    // 2xx 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
    // 응답 데이터가 있는 작업 수행
    return response;
  }, function (error) {
    // 2xx 외의 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
    // 응답 오류가 있는 작업 수행
    return Promise.reject(error);
  });

인터셉터 제거

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

에러 핸들링

axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // 요청이 전송되었고, 서버는 2xx 외의 상태 코드로 응답했습니다.
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // 요청이 전송되었지만, 응답이 수신되지 않았습니다. 
      console.log(error.request);
    } else {
      // 오류가 발생한 요청을 설정하는 동안 문제가 발생했습니다.
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

validateStatus

validateStatus config 옵션을 사용하면, 특정 코드에 대한 반환을 재정의 할 수있다.

axios.get('/user/12345', {
  validateStatus: function (status) {
    return status < 500; // 상태 코드가 500 미만인 경우 resolve됌 
    //(상태코드 500미만은 error로 처리하지않음)
  }
})

더 많은 에러 정보 얻기

toJSON을 사용하면, HTTP 에러에 대한 더 많은 정보를 객체 형식으로 가져온다.

axios.get('/user/12345')
  .catch(function (error) {
    console.log(error.toJSON());
  });

URL-인코딩 바디

URL Query Params 보내기

import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  'https://example.com',
};
axios(options);
//요청 data : https://example.com?bar=123

Form Data 보내기

const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', files[0]);

axios.post('https://example.com', form, { headers: {"Content-Type": "multipart/form-data"} })

0개의 댓글