이번 글에서는 CMC에서 처음 알게되었고 사용한 AxiosInstance
에 대해 기술해보려고 합니다.
AxiosInstance
에 대해 알아보기 전에 axios
에 대해 간략하게 알아보고 넘어가봅시다.
axios
는 HTTP 요청을 보낼 때 매우 유용한 JS 라이브러리인데, 이를 통해 API와의 통신을 간단하고 직관적으로 처리할 수 있습니다.axios
의 강력한 기능 중 하나는 axios.create
메서드를 사용해 기본 설정이 포함된 인스턴스를 생성할 수 있다는 점입니다.
이 인스턴스를 통해 공통 설정을 재사용하고, 요청과 응답을 전역적으로 처리하는 interceptors
를 쉽게 관리할 수 있습니다.
우선 제가 프로젝트에서 사용한 코드를 보며 하나하나 살펴봅시다.
import axios from 'axios';
export const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
withCredentials: true,
});
axiosInstance 생성
먼저, axios.create
메서드를 사용해 axiosInstance
를 생성합니다.
1-1. baseURL
baseURL
은 모든 요청의 기본 URL이 됩니다. import.meta.env.VITE_API_BASE_URL
에서 환경 변수를 통해 이 값을 동적으로 설정할 수 있는데 이를 통해 개발 환경과 프로덕션 환경에서 다른 API URL을 쉽게 설정할 수 있습니다.
1-2. withCredentials
withCredentials
옵션은 요청에 인증 정보 (예: 쿠키, 인증 header)를 포함시킬지 여부를 확인합니다.
이 옵션은 CORS 요청을 다룰 때 유용합니다.
인터셉터(Interceptors)
2-1. 요청 인터셉터(Request Interceptor)
axiosInstance.interceptors.request.use(
config => {
// 요청이 서버로 보내지기 전에 실행되는 로직
// 예: Authorization 헤더 추가
config.headers.Authorization = `Bearer ${window.localStorage.getItem('token')}`;
return config; // config를 반환하면 다음 단계로 요청이 진행됩니다.
},
error => {
// 요청이 실패했을 때 실행되는 로직
console.error('[AXIOS_ERROR]: ', error);
return Promise.reject(error); // 오류를 반환하여 호출자에게 전달
}
);
요청 인터셉터는 모든 요청이 서버로 전송되기 전에 호출됩니다. 주로 인증 토큰을 추가하거나 요청을 로깅하는데 사용됩니다.
use
메서드
use
메서드는 인터셉터를 등록할 때 사용하는 메서드로 두 가지 콜백 함수를 인수로 받습니다.
첫 번째 인수
요청이 서버로 보내지기 전에 실행되는 함수입니다. 이 함수는 config
객체를 매개변수로 받으며, 이 객체를 수정하거나 그대로 반환할 수 있습니다.
두 번째 인수
요청이 실패했을 때 실행되는 함수입니다. 이 함수는 오류를 처리하거나 그대로 반환하여 호출자에게 전달할 수 있습니다.
(수정) 개념 설명만으로는 이해가 어려울 것 같아 코드에 주석을 추가했습니다.
2-2. 응답 인터셉터(Response Interceptor)
axiosInstance.interceptors.response.use(
response => {
// 사용자가 `/members/login` 경로로 로그인 요청을 보냈을 때, 서버로부터 받은 응답에서 인증 토큰을 `localstorage`에 저장합니다.
if (response.config.url === '/members/login') {
window.localStorage.setItem('token', response.data.data.token);
}
return response;
},
error => {
if (error.response) {
if (error.response.status === 500) {
console.error('[AXIOS_ERROR_500]: ', error.response.data);
}
} else if (error.request) {
console.error('[AXIOS_ERROR_NO_RES]:', error.request);
} else {
console.error('[AXIOS_ERROR_NET]: ', error.message);
}
return Promise.reject(error);
}
);
응답 인터셉터는 서버로부터 응답을 받은 후 실행됩니다.
저 같은 경우는 response
에서 /members/login
경로로 로그인 요청을 보냈을 때, 서버로부터 받은 응답에서 인증 token
을 localstorage
에 저장합니다. 이 token
은 이후 모든 요청에 사용됩니다.
오류 처리
- 응답에서 오류가 발생한 경우 상태 코드에 따라 적절한 처리를 합니다.
- 예시로는 500, 500 이외의 에러가 있습니다.
axiosInstance 사용하기
이제 axiosInstance
를 사용해봅시다.
// 로그인
export const signin = async (payload: SigninType) => {
const { data } = await axiosInstance.post('/members/login', payload);
return data;
};
필자의 경우 로그인 요청을 보낼 때 사용되는 코드를 가져왔다.
signin
함수
이 함수에서는 SigninType
이라는 타입의 payload
를 인수로 받습니다. 이 payload
에는 로그인에 필요한 사용자 정보를 포함합니다.
비동기 함수 async
를 사용했으며 내부에서는 await
키워드를 사용해 비동기 요청을 처리합니다.
사전에 설정한 axiosInstance
를 사용하여 엔드포인트로 POST
요청을 보냅니다.
await
키워드
await
는 비동기 요청이 완료될 때까지 함수의 실행을 일시 중지시킵니다.
요청이 성공적으로 완료되면 서버로부터의 응답이 반환되고, 응답 객체에서 data
속성만을 구조 분해 할당하여 사용합니다.
return data
서버로부터 받은 응답 데이터 data
를 반환합니다.
이 data
에는 서버가 로그인 요청에 대해 반환하는 인증 토큰이나 사용자 정보가 포함될 수 있습니다.
응답 받은 데이터 data
는 useSignin
이라는 커스텀 훅에서 사용되는데 react-hook-form
, react-query
, zod
등 여러가지와 조합되어 있기 때문에 이 글에서 설명하기에는 조금 설명이 부족한 것 같아 이후 작성할 글에 이 글의 URL을 첨부하여 덧붙여 설명하려고 합니다.
장점과 활용 사례
3.1 장점
- 코드 재사용성 증가 : 여러 컴포넌트에서 동인한
axiosInstance
를 사용하여 코드 중복을 줄이고 유지 보수를 용이하게 합니다. - 중앙집중식 관리 : 토큰, 에러 처리 로깅 등을 중앙에서 관리할 수 있어 일관된 요청 및 응답 처리가 가능합니다.
3.2 활용 사례
- 사용자 인증이 필요한 API 호출 : 인증이 필요한 모든 API 요청에 자동으로 토큰을 포함시킬 수 있습니다.
- 글로벌 에러 핸들링 : 모든 API 요청의 오류를 중앙에서 처리하고, 사용자에게 알림을 띄우는 등의 일관된 에러 처리 로직을 구현할 수 있습니다.
- 로깅 및 분석 : 모든 요청과 응답을 인터셉터에서 로깅하여 서버의 성능이나 오류 발생 현황을 추적할 수 있습니다.
결론
axios
만을 사용해 본 저로서는 꽤나 신선한 경험이었던 것 같습니다. CMC에서 진행한 프로젝트가 아닌 또 다른 사이드 프로젝트에선 axios
만을 사용하여 굉장히 난잡한 코드를 보여줍니다. 9월 이후 refactor
예정인데 axiosInstance
를 사용해 조금 더 유지보수와 간결성에 집중하려고 합니다.
레퍼런스
더 많은 자료를 원하신다면 아래 링크를 참고하시면 될 것 같습니다.
이번 글에서는 CMC에서 처음 알게되었고 사용한 AxiosInstance
에 대해 기술해보려고 합니다.
AxiosInstance
에 대해 알아보기 전에 axios
에 대해 간략하게 알아보고 넘어가봅시다.
axios
는 HTTP 요청을 보낼 때 매우 유용한 JS 라이브러리인데, 이를 통해 API와의 통신을 간단하고 직관적으로 처리할 수 있습니다.axios
의 강력한 기능 중 하나는 axios.create
메서드를 사용해 기본 설정이 포함된 인스턴스를 생성할 수 있다는 점입니다.
이 인스턴스를 통해 공통 설정을 재사용하고, 요청과 응답을 전역적으로 처리하는 interceptors
를 쉽게 관리할 수 있습니다.
우선 제가 프로젝트에서 사용한 코드를 보며 하나하나 살펴봅시다.
import axios from 'axios';
export const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
withCredentials: true,
});
axiosInstance 생성
먼저, axios.create
메서드를 사용해 axiosInstance
를 생성합니다.
1-1. baseURL
baseURL
은 모든 요청의 기본 URL이 됩니다. import.meta.env.VITE_API_BASE_URL
에서 환경 변수를 통해 이 값을 동적으로 설정할 수 있는데 이를 통해 개발 환경과 프로덕션 환경에서 다른 API URL을 쉽게 설정할 수 있습니다.
1-2. withCredentials
withCredentials
옵션은 요청에 인증 정보 (예: 쿠키, 인증 header)를 포함시킬지 여부를 확인합니다.
이 옵션은 CORS 요청을 다룰 때 유용합니다.
인터셉터(Interceptors)
2-1. 요청 인터셉터(Request Interceptor)
axiosInstance.interceptors.request.use(
config => {
// 요청이 서버로 보내지기 전에 실행되는 로직
// 예: Authorization 헤더 추가
config.headers.Authorization = `Bearer ${window.localStorage.getItem('token')}`;
return config; // config를 반환하면 다음 단계로 요청이 진행됩니다.
},
error => {
// 요청이 실패했을 때 실행되는 로직
console.error('[AXIOS_ERROR]: ', error);
return Promise.reject(error); // 오류를 반환하여 호출자에게 전달
}
);
요청 인터셉터는 모든 요청이 서버로 전송되기 전에 호출됩니다. 주로 인증 토큰을 추가하거나 요청을 로깅하는데 사용됩니다.
use
메서드
use
메서드는 인터셉터를 등록할 때 사용하는 메서드로 두 가지 콜백 함수를 인수로 받습니다.
첫 번째 인수
요청이 서버로 보내지기 전에 실행되는 함수입니다. 이 함수는 config
객체를 매개변수로 받으며, 이 객체를 수정하거나 그대로 반환할 수 있습니다.
두 번째 인수
요청이 실패했을 때 실행되는 함수입니다. 이 함수는 오류를 처리하거나 그대로 반환하여 호출자에게 전달할 수 있습니다.
(수정) 개념 설명만으로는 이해가 어려울 것 같아 코드에 주석을 추가했습니다.
2-2. 응답 인터셉터(Response Interceptor)
axiosInstance.interceptors.response.use(
response => {
// 사용자가 `/members/login` 경로로 로그인 요청을 보냈을 때, 서버로부터 받은 응답에서 인증 토큰을 `localstorage`에 저장합니다.
if (response.config.url === '/members/login') {
window.localStorage.setItem('token', response.data.data.token);
}
return response;
},
error => {
if (error.response) {
if (error.response.status === 500) {
console.error('[AXIOS_ERROR_500]: ', error.response.data);
}
} else if (error.request) {
console.error('[AXIOS_ERROR_NO_RES]:', error.request);
} else {
console.error('[AXIOS_ERROR_NET]: ', error.message);
}
return Promise.reject(error);
}
);
응답 인터셉터는 서버로부터 응답을 받은 후 실행됩니다.
저 같은 경우는 response
에서 /members/login
경로로 로그인 요청을 보냈을 때, 서버로부터 받은 응답에서 인증 token
을 localstorage
에 저장합니다. 이 token
은 이후 모든 요청에 사용됩니다.
오류 처리
- 응답에서 오류가 발생한 경우 상태 코드에 따라 적절한 처리를 합니다.
- 예시로는 500, 500 이외의 에러가 있습니다.
axiosInstance 사용하기
이제 axiosInstance
를 사용해봅시다.
// 로그인
export const signin = async (payload: SigninType) => {
const { data } = await axiosInstance.post('/members/login', payload);
return data;
};
필자의 경우 로그인 요청을 보낼 때 사용되는 코드를 가져왔다.
signin
함수
이 함수에서는 SigninType
이라는 타입의 payload
를 인수로 받습니다. 이 payload
에는 로그인에 필요한 사용자 정보를 포함합니다.
비동기 함수 async
를 사용했으며 내부에서는 await
키워드를 사용해 비동기 요청을 처리합니다.
사전에 설정한 axiosInstance
를 사용하여 엔드포인트로 POST
요청을 보냅니다.
await
키워드
await
는 비동기 요청이 완료될 때까지 함수의 실행을 일시 중지시킵니다.
요청이 성공적으로 완료되면 서버로부터의 응답이 반환되고, 응답 객체에서 data
속성만을 구조 분해 할당하여 사용합니다.
return data
서버로부터 받은 응답 데이터 data
를 반환합니다.
이 data
에는 서버가 로그인 요청에 대해 반환하는 인증 토큰이나 사용자 정보가 포함될 수 있습니다.
응답 받은 데이터 data
는 useSignin
이라는 커스텀 훅에서 사용되는데 react-hook-form
, react-query
, zod
등 여러가지와 조합되어 있기 때문에 이 글에서 설명하기에는 조금 설명이 부족한 것 같아 이후 작성할 글에 이 글의 URL을 첨부하여 덧붙여 설명하려고 합니다.
장점과 활용 사례
3.1 장점
- 코드 재사용성 증가 : 여러 컴포넌트에서 동인한
axiosInstance
를 사용하여 코드 중복을 줄이고 유지 보수를 용이하게 합니다. - 중앙집중식 관리 : 토큰, 에러 처리 로깅 등을 중앙에서 관리할 수 있어 일관된 요청 및 응답 처리가 가능합니다.
3.2 활용 사례
- 사용자 인증이 필요한 API 호출 : 인증이 필요한 모든 API 요청에 자동으로 토큰을 포함시킬 수 있습니다.
- 글로벌 에러 핸들링 : 모든 API 요청의 오류를 중앙에서 처리하고, 사용자에게 알림을 띄우는 등의 일관된 에러 처리 로직을 구현할 수 있습니다.
- 로깅 및 분석 : 모든 요청과 응답을 인터셉터에서 로깅하여 서버의 성능이나 오류 발생 현황을 추적할 수 있습니다.
결론
axios
만을 사용해 본 저로서는 꽤나 신선한 경험이었던 것 같습니다. CMC에서 진행한 프로젝트가 아닌 또 다른 사이드 프로젝트에선 axios
만을 사용하여 굉장히 난잡한 코드를 보여줍니다. 9월 이후 refactor
예정인데 axiosInstance
를 사용해 조금 더 유지보수와 간결성에 집중하려고 합니다.
레퍼런스
더 많은 자료를 원하신다면 아래 링크를 참고하시면 될 것 같습니다.