-
Notifications
You must be signed in to change notification settings - Fork 2
axios interceptor커스텀하기
axios interceptor 커스텀하기
이번에 axios interceptor를 사용하여 중복되는 header들을 하나로 합치고자 했다.
따라서 맨처음에 생각한 로직은
- 토큰을 페이지에서 불러온다.
- 토큰을 config에 넣어보낸다.
- 인터셉터에서 config.token을 Authorization키의 값을 넣는다.
이렇게 생각했던 이유는 인터셉터에서 토큰을 localstorage에서 가져오는것은 인터셉터의 책임이 아니라고 생각했다.
(하지만 추후에 논의한 결과 인터셉터안에서 토큰을 불러오는것이 더 효율적이라는 의견으로 통일되어 변경하였다.)
내가 설계했던 방법은 처음부터 어떻게 페이지에서 사용할 것이다.
라고 정의 후 인스턴스를 만드는 것이었다.
따라서 페이지에서는 아래와 같이 닉네임과 토큰을 파라미터로 전달해주고 싶었다.
//토큰을 localstorage에서 불러오는 로직
signUpApi(nickname, token)
따라서 나는 우선 인스턴스 만들어 주었다.
const createAuthInstance = () => {
const instance = axios.create({ baseURL: process.env.REACT_APP_BASE_URL });
authInterceptor(instance);
return instance;
};
export const authInstance = createAuthInstance();
그 후 아래와 같은 함수를 만들어 주었다.
authInstance.post('/api/v1/users/signup', { nickname }, { token })
하지만 이렇게 했더니 아래와 같은 에러가 나왔다.
따라서 axios에 정의되어있는 타입들을 보며 하나하나 맞춰나갔다.
맨처음에 axiosInstance를 사용하니 그 타입을 상속받아서 재정의하면 간단히 해결될 줄 알았다.
// 정의되어있는 AxiosInstance
interface AxiosInstance extends Axios {
(config: AxiosRequestConfig): AxiosPromise;
(url: string, config?: AxiosRequestConfig): AxiosPromise;
}
//정의되어있는 axiosRequestConfig
export interface AxiosRequestConfig<D = any> {
url?: string;
method?: Method;
baseURL?: string;
...
}
// 재정의하기
interface CustomAxiosRequestConfig extends AxiosRequestConfig{
token: string
}
interface CustomAxiosInstance extends AxiosInstance{
(config: CustomAxiosRequestConfig): AxiosPromise;
(url: string, config?: CustomAxiosRequestConfig): AxiosPromise;
}
하지만 이렇게 함에도 불구하고 에러는 여전히 사라지지 않았다.
따라서 axiosInstance가 상속받고 있는 Axios를 살펴보았다.
export class Axios {
constructor(config?: AxiosRequestConfig);
defaults: AxiosDefaults;
interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
delete<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
head<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
options<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
patch<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
}
이렇게 정의가 되어있는데, 우리가 결국 사용하는 axiosInterceptor의 config는 이 Axios때문에 AxiosRequestConfig타입을 유지하고 있어 타입에러가 났다고 생각했다.
따라서 내가 해결한 방법은
type.ts 파일안에
export interface CustomAxiosRequestConfig extends AxiosRequestConfig {
token: string;
}
export interface CustomInstance extends AxiosInstance {
interceptors: {
request: AxiosInterceptorManager<CustomAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse<any>>;
};
getUri(config?: CustomAxiosRequestConfig): string;
request<T>(config: CustomAxiosRequestConfig): Promise<T>;
get<T>(url: string, config?: CustomAxiosRequestConfig): Promise<T>;
delete<T>(url: string, config?: CustomAxiosRequestConfig): Promise<T>;
head<T>(url: string, config?: CustomAxiosRequestConfig): Promise<T>;
options<T>(url: string, config?: CustomAxiosRequestConfig): Promise<T>;
post<T>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<T>;
put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
patch<T>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<T>;
}
이렇게 instance가 사용할 메서드들의 configType을 재정의 해주었다.
그 후 아래와 같이 instance에 대한 타입 단언을 해주었다.
const createAuthInstance = () => {
const instance = axios.create({ baseURL: process.env.REACT_APP_BASE_URL }) as CustomInstance;
authInterceptor(instance);
return instance;
};
마지막으로 인터엡터에서 instance의 타입을 지정해주면 된다!
const authInterceptor = (instance: CustomInstance) => {
instance.interceptors.request.use((config) => {
config.headers = {
authorization: `Bearer ${config.token}`,
...config.headers,
};
return config;
});
};
사실 이 프로젝트를 하면서 타입스크립트를 처음 하다 보니 이렇게 하는것이 올바른 방법인지는 잘 모르겠다,,😅😅
또한 결국 token을 가져오는 로직을 페이지에서 가져오는것이 아니라 interceptor안에서 일괄적으로 처리를 해주었기 때문에 현재는 더이상 custom interceptor가 필요한 상황은 아니다.
하지만 언제 다시 커스텀을 해야할지 모르기 때문에 기록은 해두자..!
고민의 흔적
만난 이슈들
- [소정]emotion theme 적용이 왜 안될까?
- [동진]addEventListener의 passive 속성과 preventDefault
- [동진]storybook - defaultValue is deprecated!
- [소정, 정호]배포시 mapbox가 동작하지 않던 문제!
- [동진]axios interceptor를 설정하면서 만났던 config타입정의 문제
- [정호]Input 값에 undefined나 null이 들어오는 경우 발생하는 오류
- [정호]Javascript에서 KST , TOMORROW 구하는 방법
- [동진]시멘틱한-dropdown만들기!