axios 사용기

Gn0lee·2023년 5월 7일
0

Tech 이모저모

목록 보기
14/18
post-thumbnail

axios를 사용해 왔던 방법

프론트엔드에서 가장 흔하게 사용하는 라이브러리 중 하나는 axios일 것이다. 나의 팀도 axios를 당연하게 사용하였다. 하지만 사용하다보니 중복되는 코드가 많았고 과연 axios를 유용하게 사용하고 있는것이 맞는지 의문이었다.

매번 설정하는 default setting

기존에는 api한개당 한개의 api 파일이 있었다. 그리고 해당 파일에서 api에 필요한 설정을 해주었으며 필요한 값이 없는 경우 에러를 던지는 코드를 작성해 주었다. 모든 api 함수에 동일하게 작성되었다. 어차피 복붙해서 사용했지만 시간이 지나면서 비효율적이라는 의견이 나왔고 나도 이에 동감했다.

import axios, { AxiosError } from 'axios';
import { GetApiResponse } from 'api.type';

import { TOKEN, USER_KEY } from 'common/data/constants';

export default async function getTodosApi() {
	const accessToken = window.sessionStorage.getItem(TOKEN);
	const userKey = window.sessionStorage.getItem(USER_KEY);

	if (accessToken && userKey) {
		const { data } = await axios.get<GetApiResponse>(
			`${process.env.REACT_APP_BASE_URL}/todos`,
			{
				headers: {
					Authorization: accessToken,
					userKey,
				},
			}
		);
		return data;
	}

	throw AxiosError.ERR_BAD_OPTION_VALUE;
}

세션 스토리지에 저장하는 인증 토큰과 유저키를 getTodosApi에서 확인하고 값이 없다면 에러를 던졌다. 그리고 axios에서 사용하는 url은 환경변수와 api path를 조합하여 매번 작성했다. 모든 api 호출 함수에서 환경변수값을 참조했다.

api 개발 전 작업방식

작업 일정 상 api가 개발 되기전 프론트엔드 작업이 시작되었다. 그렇다 보니 mock data로 작업을 했다. Mock data만으로는 유저가 행하는 액션을 반영할수가 없었다. 고정된 화면에 대한 내용만 확인이 가능했으며 api가 개발 되기 전에는 api 함수, thunk, react-query를 적용하기 어려웠다.

해결방법

위의 두가지 문제를 해결하고자 axios의 instance와 axios-mock-adpator를 활용하였다. axios instance를 통해 중복 코드를 제거할 수 있었고 동일한 에러에 대해 동일한 동작을 미리 지정할 수 있었다. 그리고 axios-mock-adaptor를 통해 간단한 mock api를 직접 작성하여 api 개발 전에도 api 함수를 제외하고 모두 작업할 수 있었다.

axios instance

axios instance를 만들어 프로젝트 내에서 공동으로 사용하기 시작했다. 일일이 작성했던 url, 고정 헤더를 한번만 작성하면 해결되었다.

export const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});

이런식으로 instance를 만들고 다른 함수에서 instance를 활용하여 api를 호출할 수 있다.

import instance from 'common/utils/axiosInstance';

export default async function getTodosApi() {
	const { data } = await axiosInstance.get<GetApiResponse>('todos');

	return data;
}

기존 토큰, 유저키가 없을때 처리는 instace의 interceptor를 활용하였다. 기존에는 api 요청 전에 에러를 반환하였지만 지금은 api의 에러코드를 바탕으로 동작을 지정하였다. 이것은 작업자의 취향차이일 것 같다. 나는 react-query를 사용하여 retry와 같이 사용하다보니 에러 코드를 활용하였다.

instance.interceptors.response.use(
	response => {
		return response;
	},
	error => {
		if (error?.response?.data?.errorCode === '필수값 없음') {
			const token = window.sessionStorage.getItem(TOKEN);
			const userKey = window.sessionStorage.getItem(USER_KEY);

			if (cognitoToken === null || userKey === null) {
				window.location.replace('/');
			}

			instance.defaults.headers.Authorization = cognitoToken;
			instance.defaults.headers.userKey = userKey;
		}

		return Promise.reject(error);
	}
);

axios에서 에러를 반환하기 전에 미리 에러코드를 보고 필요한 동작을 추가하였다. 위의 예제어서는 필수값 없음 코드일 때 필수값을 instance의 헤더에 추가한 후 에러를 반환하고 react-query에서 해당 api를 다시 시도하므로 문제가 해결된다.

위의 예시는 reponse를 intercept했지만 request에서도 가능하다.

axios-mock-adaptor

보통 axios-mock-adaptor는 테스트를 위한 용도로 많이 사용된다. 하지만 팀 내에서는 api가 없을때 api의 역할을 대신할 수 있는 도구가 필요하였고 axios-mock-adaptor를 선택하였다. 간단한 사용법과 내가 사용하며 알게 된 점을 몇가지 소개하려 한다.

사용법

우선 mock api를 위한 axios instance를 만든 후 MockAdaptor에 연결한다.

import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';

const axiosMockInstance = axios.create();

const mockInstance = new MockAdapter(axiosMockInstance);

export { axiosMockInstance, mockInstance };

그리고 원하는 api에서 mockInstance의 동작을 지정해준다.


import type { GetTodoListApiResponse } from 'types/getTodoList.type';

import { mockInstance, axiosMockInstance } from 'axiosInstance';

import { MOCK_TODO_LIST } from 'data/mock';

mockInstance.onGet('/todo/list').reply(
	() =>
		new Promise(resolve => {
			resolve([
				200,
				{
					data: [...MOCK_TODO_LIST],
				},
			]);
		})
);

export async function getTodoListMockApi() {
	const { data } = await axiosMockInstance.get<GetTodoListApiResponse>(`/todo/list`);

	return data;
}

알게된 점

  1. 패턴은 되도록 정규 표현식으로
    onGet의 패턴에는 문자열이나 정규 표현식을 사용가능한데 되도록 정규표현식을 사용하는것이 좋다. 쿼리 파라미터가 붙는 경우 문자열과 정확히 일치하지 않으면 인식을 못한다. 쿼리 파라미터나 패스 파라미터가 고정인 경우는 괜찮지만 동적인 경우는 정규 표현식으로 나타내야 인식이 가능하다.

  2. 에러 반환하는 법
    에러를 반환하려면 resolve 대신 reject를 사용하면 된다. 다만 reject에 에러코드를 추가하고 싶은데 이 방법은 아직 찾는 중이다.
    에러를 반환하기 위해선 resolve의 status code 값을 수정하면 된다. 400 ~ 500 번대로 수정하면 axios에서 에러로 인식한다.

mock api를 적용하고 나서 부터는 api 개발이 완료 전에도 개발이 거의 끝나며 api 개발이 완료되면 api 함수만 교체해주면 되어 매우 편리했다.

후기

처음에는 axios를 그저 api 호출용도로 사용하였는데 어떻게 사용하느냐에 따라 작업환경을 개선할 수 있다는 것을 알았다. 아직 사용해보지 못한 기능들이 많아서 나중에 더욱 발전시켜보고싶다.

profile
정보보다는 경험을 공유하는 테크 블로그입니다.

0개의 댓글