utils
사실 Axios의 기초를 다루기엔 구글에 자료들이 많기 때문에 사용에 도움이 될 부분들 위주로 적어보려 합니다. Axios를 사용하기는 굉장히 쉽기 때문에 현업에서도 자주 사용하는 방법 중 하나입니다. 하지만 잘 사용하기 위해서는 사용자에게 제공되는 Application에 대한 여러 고민들이 필요합니다.
개발자는 반복되는 코드를 줄이고 효율적인 코드를 작성하기 위해 노력합니다. Axios에서는 토큰을 헤더에 포함시키는 경우와 공통 에러처리를 하는 경우에 중복된 코드가 발생합니다. 이러한 중복 제거와 효율적인 관리를 위해 Axios 인스턴스와 인터셉터를 사용하게 된다. 이러한 표현을 조금 더 전문적으로 표현하자면, 횡단 관심사 분리(cross-cutting concern)를 반영한 개발이라고도 표현 합니다.
클래스와 인스턴스의 관계를 생각해 보면, 인스턴스를 사용하는 이유는 중복된 코드 방지라고 할 수 있습니다. Axios 라이브러리 내부에 사용되는 클래스가 정의 되어 있고, 이러한 클래스를 기반으로 사용자가 원하는 인스턴스를 생성할 수 있습니다. 이러한 인스턴스를 기반으로 baseUrl, header, body, params 등을 여러가지를 추가 할 수 있게 됩니다.
간단한 인스턴스를 axios로 만들어 봅시다.
// /api/axios.js
import axios from 'axios'
const paymentURL = process.env.REACT_APP_BASE_URL
const paymentInstance = axios.create({
baseURL: paymentURL,
params: {
id: 'hanpy@abc.com',
},
})
export default paymentInstance
const requests = {
fetchCredit: '/api/credits',
fetchSubscript: '/api/subscripts',
fetchPlan: '/api/plans',
}
export default requests
const res = await paymentInstance.get(requests.fetchCredit)
Axios를 사용하는 방식은 다양합니다. api를 직접 사용한다고 가정하고 적어보도록 하겠습니다.
const API = {
getUser: () => {},
getNewAccessToken: () => {},
}
import { getToken, isTokenExpired, tokenRefresh } from './token'
const API_ACCOUNT_URL = process.env.REACT_APP_ACCOUNT_URL
const createInstance = () => {
const instance = axios.create({
baseURL: API_ACCOUNT_URL,
timeout: 3000,
})
setInterceptors(instance)
return instance
}
const setInterceptors = (instance: AxiosInstance) => {
instance.interceptors.response.use(
(response) => {
if (response.status === 404) {
window.location.href = '/error/404'
}
return response
},
(error) => {
if (error.response?.status === 401) {
if (isTokenExpired()) await tokenRefresh()
const accessToken = getToken()
error.config.headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
}
const response = await axios.request(error.config)
return response
}
return Promise.reject(error)
},
)
instance.interceptors.request.use(
(config) => {
const accessToken = getToken()
config.headers['Content-Type'] = 'application/json'
config.headers['Authorization'] = `Bearer ${accessToken}`
return config
},
(error: AxiosError) => {
console.log('interceptor > error', error)
Promise.reject(error)
},
)
}
export const clientInstance = createInstance()
const API = {
getUser: async () => {
const { data } = await clientInstance.get(`/v1/user/access_token_info`)
return data
},
getNewAccessToken: async ({ refreshToken }: { refreshToken: string }) => {
const { data } = await clientInstance.post(`/oauth/token`, {
refreshToken: `Bearer ${refresh_token}`,
grantType: 'refresh_token',
})
return data
},
}
export default API