import axios from 'axios'; import qs from 'qs'; const instance = axios.create({ baseURL: process.env.REACT_APP_API_URL || 'http://localhost:8000', headers: { 'Content-Type': 'application/json', }, }); // Token refresh mechanism let isRefreshing = false; let failedQueue: any[] = []; const processQueue = (error: any, token: string | null = null) => { failedQueue.forEach(prom => { if (error) { prom.reject(error); } else { prom.resolve(token); } }); failedQueue = []; }; // Add a request interceptor instance.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } // Handle form data if (config.data instanceof FormData) { config.headers['Content-Type'] = 'application/x-www-form-urlencoded'; config.data = qs.stringify(Object.fromEntries(config.data)); } return config; }, (error) => { return Promise.reject(error); } ); // Add a response interceptor instance.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; if (error.response?.status === 401 && !originalRequest._retry) { if (isRefreshing) { return new Promise((resolve, reject) => { failedQueue.push({ resolve, reject }); }) .then(token => { originalRequest.headers.Authorization = `Bearer ${token}`; return instance(originalRequest); }) .catch(err => Promise.reject(err)); } originalRequest._retry = true; isRefreshing = true; try { const refreshToken = localStorage.getItem('refreshToken'); if (!refreshToken) { throw new Error('No refresh token available'); } const response = await axios.post('/api/auth/refresh', { refresh_token: refreshToken, }); const { access_token, refresh_token } = response.data; localStorage.setItem('token', access_token); localStorage.setItem('refreshToken', refresh_token); instance.defaults.headers.common.Authorization = `Bearer ${access_token}`; processQueue(null, access_token); return instance(originalRequest); } catch (refreshError) { processQueue(refreshError, null); localStorage.removeItem('token'); localStorage.removeItem('refreshToken'); window.location.href = '/login'; return Promise.reject(refreshError); } finally { isRefreshing = false; } } return Promise.reject(error); } ); // Error handling utility export const handleApiError = (error: any): string => { if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx return error.response.data.message || 'An error occurred while processing your request'; } else if (error.request) { // The request was made but no response was received return 'No response received from server. Please check your internet connection'; } else { // Something happened in setting up the request that triggered an Error return error.message || 'An unexpected error occurred'; } }; export default instance;