개발을 진행하면서 HTTP 요청을 다루게 되는데, 이때 많은 경우에 반복되는 패턴이나 코드를 발견할 수 있다. 토큰을 헤더에 포함시키거나, 공통된 에러처리 등이 그 예다.
이러한 반복적인 코드를 줄이고, 더 효과적으로 코드를 관리하기 위해 Axios 인스턴스와 인터셉터를 사용하는 방법에 대해 알아보자.
Axios 인스턴스 생성
먼저, 반복적으로 사용되는 Axios 설정을 추상화하기 위해 Axios 인스턴스를 생성한다. Axios 인스턴스는 주어진 설정으로 초기화된 새로운 Axios 요청을 만들어낸다. 이렇게 생성된 인스턴스는 설정이 미리 적용되어 있으므로, 각 요청에서 이 설정을 반복하지 않아도 된다.
// customApi.ts
import axios, { AxiosInstance } from 'axios';
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL; // Next 사용중인 프로젝트
const createInstance = () => {
const instance = axios.create({
baseURL: API_BASE_URL,
timeout: 2000,
});
return instance;
};
export const clientInstance = createInstance();
위의 코드에서는 기본 URL 및 타임아웃을 설정했다. 기본 URL은 모든 요청의 URL 앞에 추가되며, 타임아웃은 요청을 취소하는 데 걸리는 시간을 설정한다.
인터셉터 설정
인터셉터는 요청이나 응답을 처리하기 전에 실행되는 함수다. 이를 이용하면 중복되는 코드를 줄일 수 있으며, 요청 또는 응답을 더 세밀하게 제어할 수 있다.
// customApi.ts
const setInterceptors = (instance: AxiosInstance) => {
instance.interceptors.response.use(
(response) => response,
(error) => {
console.log('interceptor > error', error);
return Promise.reject(error);
}
);
instance.interceptors.request.use(
(config) => {
const token = '???'; // 토큰 주입 (프로젝트 정책마다 다름)
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error: AxiosError) => {
console.log('interceptor > error', error);
Promise.reject(error);
}
);
};
const createInstance = () => {
const instance = axios.create({
baseURL: API_BASE_URL,
timeout: 2000,
});
setInterceptors(instance);
return instance;
};
위의 코드에서는 요청 인터셉터와 응답 인터셉터를 설정했다.
- 요청 인터셉터는 요청이 서버로 보내지기 전에 호출된다. 여기서는 토큰이 존재하면 이를 헤더에 추가하는 로직을 추가하였다.
- 응답 인터셉터는 서버로부터 응답을 받은 후에 호출된다. 여기서는 오류가 발생하면 콘솔에 오류 메시지를 출력하도록 하였다.
-> 요청에 실패하면 console에 어떤 오류가 발생했는 지 바로 찍히기 때문에 디버깅이 아주 수월해진다.
API 요청 함수 생성
마지막으로, 앞서 생성한 인스턴스를 이용하여 API 요청 함수를 만든다.
// 예시
// API.ts
const API = {
getUserProfile: async (nickname: string) => {
const { data } = await clientInstance.get(`user/${nickname}`);
return data;
}
};
export default API;
이 함수를 이용하면 인스턴스를 생성할 때 설정한 기본 URL과 타임아웃, 그리고 인터셉터가 자동으로 적용된 요청을 보낼 수 있다.
추가로, API함수를 정의하다보면 header에 특별한 값을 넣어야 할 때가 있을 수 있는데 그때는 API 함수에다가 header를 넣어주면 덮어 쓰이기 때문에 API에 직접 작성하면 된다.
// API.ts
const API = {
getUserProfile: async (nickname: string) => {
const { data } = await clientInstance.get(`user/${nickname}`);
return data;
},
// 직접 주입
getNewAccessToken: async ({
refreshToken,
accessToken,
}: {
refreshToken: string;
accessToken: string;
}) => {
const { data } = await clientInstance.post(
`/publish/access-token`,
{ accessToken: `Bearer ${accessToken}` },
{
headers: {
Authorization: `Bearer ${refreshToken}`,
},
}
);
return data;
},
};
export default API;
Axios의 인스턴스와 인터셉터를 이용하면 중복되는 코드를 줄이고, 코드를 더 간결하고 관리하기 쉽게 만들 수 있다. 이러한 방법을 통해 코드의 횡단 관심사를 분리하여 개발 과정을 더 효율적으로 만들어 보자.
참고한 사이트
https://axios-http.com/docs/interceptors
https://axios-http.com/docs/instance
'토이프로젝트 > LinkArchive' 카테고리의 다른 글
[문제 해결] Warning: An update to Profile inside a test was not wrapped in act(...). (1) | 2023.07.18 |
---|---|
Redux Provider로 감싸진 컴포넌트 테스트하기 (0) | 2023.07.15 |
Next.js에서 토큰 재발급 구현하기 (3) | 2023.06.14 |