89 lines
2.6 KiB
TypeScript

/* eslint-disable consistent-return */
/* eslint-disable no-param-reassign */
import axios, { AxiosInstance } from 'axios';
import { staticMessages } from '~/driven/utils/constants/staticMessages';
import { ApiGlobalResponseObject } from '~/driven/utils/protocols/serviceProtocols';
import { apiUrls } from '~/driven/utils/configs/appConfig';
import { HttpOptionsType } from './protocols';
interface IUserTokens {
accessToken: string | null;
refreshToken: string | null;
}
export class HTTPPovider {
private userTokens: IUserTokens;
private updateAccessToken: (newAccessToken: string) => void;
private navigateToAuth: () => void;
constructor(
userTokens: IUserTokens,
updateAccessToken: (newAccessToken: string) => void,
navigateToAuth: () => void,
) {
this.userTokens = userTokens;
this.updateAccessToken = updateAccessToken;
this.navigateToAuth = navigateToAuth;
}
private initalizeAxiosInstance() {
const instance = axios.create();
return instance;
}
private handleRequestInterceptor() {
const axiosInstance = this.initalizeAxiosInstance();
axiosInstance.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${this.userTokens.accessToken}`;
return config;
});
return axiosInstance;
}
async request<R>(customOptions: HttpOptionsType) {
const axiosInstance = this.handleRequestInterceptor();
this.responseIncepter(axiosInstance);
const response = await axiosInstance<ApiGlobalResponseObject<R>>(customOptions);
if (!response) throw new Error(staticMessages.service.errors[500]);
return response.data.data;
}
/**
* @todo should be handled in business logic
*/
private async refreshAccessToken() {
try {
const response = await axios.post(apiUrls.generic.authRefresh, {
refresh_token: this.userTokens.refreshToken,
});
this.updateAccessToken(response.data.access_token as string);
return response.data.access_token;
} catch (err) {
this.navigateToAuth();
}
}
private responseIncepter(axiosInstance: AxiosInstance) {
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
const originalRequest = error.config;
if (error.response.status === 401 && error.response.message === 'Unauthorized') {
const newAccessToken = this.refreshAccessToken().then(() => {
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return axios(originalRequest);
});
}
return Promise.reject(error);
},
);
}
}