pmtool / src /lib /api /axios-instance.ts
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
7.13 kB
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { API_BASE_URL } from '../../config';
import { getSystemHealth } from './health';
// Mobile platform detection (simpler approach without Capacitor dependency)
const isMobileApp = () => {
return typeof window !== 'undefined' &&
(window.location.href.includes('capacitor://') ||
window.location.href.includes('ionic://') ||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
};
const isNative = isMobileApp();
// Create a custom axios instance
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
// Add additional headers for mobile apps
...(isNative && {
'X-Requested-With': 'XMLHttpRequest',
'X-Mobile-App': 'true'
})
},
timeout: 30000, // 30 seconds timeout
withCredentials: false // Disable withCredentials which can cause CORS issues
});
// Request interceptor to handle authentication for all requests
apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Get token from user_session in localStorage
const userSession = localStorage.getItem('user_session');
// Add detailed debugging
console.log(`API Request to: ${config.url}`);
console.log(`Method: ${config.method?.toUpperCase()}`);
console.log(`Running on platform: ${isNative ? 'Mobile' : 'Web'}`);
// If session exists, parse it and add token to headers
if (userSession) {
try {
const userData = JSON.parse(userSession);
console.log(`User session found: ${userData.firstName} ${userData.lastName} (${userData.email})`);
if (userData && userData.token) {
// Set Authorization header for all requests
config.headers.Authorization = `Bearer ${userData.token}`;
console.log(`Token applied: ${userData.token.substring(0, 15)}...`);
} else {
console.warn('Token missing in user session! Session data:', JSON.stringify(userData, null, 2));
}
} catch (error) {
console.error('Error parsing user session:', error);
}
} else {
console.warn('No user_session found in localStorage - request will be unauthorized');
}
// Log final headers for debugging
// console.log('Request headers:', JSON.stringify(config.headers, null, 2));
// console.log('Request URL (full):', `${config.baseURL}${config.url}`);
return config;
},
(error: AxiosError) => {
// Handle request errors
console.error('Request error:', error);
return Promise.reject(error);
}
);
// Special interceptor for the health endpoint
apiClient.interceptors.response.use(
(response: AxiosResponse) => {
const url = response.config.url;
// Check if this is a health endpoint request
if (url && (url === '/health' || url.endsWith('/health') || url === '/api/health' || url.endsWith('/api/health'))) {
console.log('Health endpoint detected, returning custom health response');
// Use the shared health implementation from health.ts
response.data = getSystemHealth();
}
return response;
},
(error) => Promise.reject(error)
);
// Response interceptor to handle authentication-related responses
apiClient.interceptors.response.use(
(response: AxiosResponse) => {
// Any status code within the range of 2xx causes this function to trigger
return response;
},
async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
// Handle 401 Unauthorized errors
if (error.response?.status === 401 && !originalRequest._retry) {
// Since we're using user_session, update refresh token logic accordingly
const userSession = localStorage.getItem('user_session');
if (userSession) {
originalRequest._retry = true;
try {
// Here you could implement token refresh logic
// Example (commented out):
/*
const userData = JSON.parse(userSession);
// Call your refresh token API
const response = await apiClient.post(
`${API_BASE_URL}/auth/refresh-token`,
{
userId: userData.userId,
// Include any other required fields
},
{
headers: {
'Content-Type': 'application/json'
}
}
);
if (response.data && response.data.token) {
// Update the token in localStorage
userData.token = response.data.token;
localStorage.setItem('user_session', JSON.stringify(userData));
// Retry the original request with new token
originalRequest.headers.Authorization = `Bearer ${response.data.token}`;
return apiClient(originalRequest);
}
*/
// For now, just clear the session and redirect to login
localStorage.removeItem('user_session');
// Redirect to login page
window.location.href = '/login';
return Promise.reject(error);
} catch (refreshError) {
// If any error during this process, clear session and redirect
localStorage.removeItem('user_session');
// Redirect to login page
window.location.href = '/login';
return Promise.reject(refreshError);
}
} else {
// No session available, redirect to login
window.location.href = '/login';
}
}
// Handle 403 Forbidden errors (permissions issue)
if (error.response?.status === 403) {
console.error('Forbidden resource:', error.config?.url);
// You can implement specific handling for forbidden resources
// For example, show an access denied notification or redirect
// window.location.href = '/access-denied';
}
// Handle 404 Not Found errors
if (error.response?.status === 404) {
console.error('Resource not found:', error.config?.url);
}
// Handle 500 and other server errors
if (error.response?.status && error.response.status >= 500) {
console.error('Server error:', error.response.status, error.config?.url);
// Optionally show a server error notification
}
// Network errors
if (error.message === 'Network Error') {
console.error('Network error - check internet connection');
// Optionally show a network error notification
}
// Timeout errors
if (error.code === 'ECONNABORTED') {
console.error('Request timeout');
// Optionally show a timeout error notification
}
return Promise.reject(error);
}
);
export default apiClient;