File size: 4,758 Bytes
25f22bf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
import axios from 'axios'
// Create axios instance
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:5000/api',
headers: {
'Content-Type': 'application/json'
},
// Disable caching for API requests to ensure we always get fresh data
adapter: 'xhr', // Use XHR adapter to avoid service worker caching issues
withCredentials: true // Send cookies with requests
})
// Add request timeout to prevent hanging requests
api.defaults.timeout = 10000 // 10 seconds timeout
// Environment-specific configuration
const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development'
const isProduction = import.meta.env.VITE_NODE_ENV === 'production'
// Debug logging function for development
const logApiCall = (config) => {
if (isDevelopment) {
console.log(`π [API] ${config.method?.toUpperCase()} ${config.url}`, {
data: config.data,
params: config.params,
headers: config.headers
})
}
}
// Error logging function for development
const logApiError = (error) => {
if (isDevelopment) {
console.error(`β [API Error] ${error.config?.url || 'Unknown URL'}`, {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
message: error.message
})
}
}
// Request interceptor to add auth token and logging
api.interceptors.request.use(
(config) => {
// Add debug logging
logApiCall(config)
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
logApiError(error)
return Promise.reject(error)
}
)
// Add token validation and refresh logic
api.interceptors.request.use(
async (config) => {
const token = localStorage.getItem('token')
if (token) {
try {
// Check if token is expired
const tokenData = JSON.parse(atob(token.split('.')[1]))
const isExpired = tokenData.exp * 1000 < Date.now()
if (isExpired) {
// Token is expired, remove it
localStorage.removeItem('token')
if (isDevelopment) {
console.log('π [Token] Token expired, removed from storage')
}
// If we're not on the login page, redirect there
if (!window.location.pathname.includes('/login')) {
window.location.href = '/login'
}
} else {
// Token is valid, add to headers
config.headers.Authorization = `Bearer ${token}`
}
} catch (error) {
// Invalid token format, remove it
localStorage.removeItem('token')
if (isDevelopment) {
console.log('π [Token] Invalid token format, removed from storage')
}
// If we're not on the login page, redirect there
if (!window.location.pathname.includes('/login')) {
window.location.href = '/login'
}
}
}
return config
},
(error) => {
logApiError(error)
return Promise.reject(error)
}
)
// Response interceptor to handle errors and logging
api.interceptors.response.use(
(response) => {
if (isDevelopment) {
console.log(`β
[API Response] ${response.config.url}`, {
status: response.status,
data: response.data
})
}
return response
},
(error) => {
logApiError(error)
if (error.response?.status === 401) {
// Only redirect if we're not already on the login page
if (!window.location.pathname.includes('/login')) {
localStorage.removeItem('token')
window.location.href = '/login'
}
}
// Add more detailed error handling for different status codes
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
const status = error.response.status
const data = error.response.data
if (isDevelopment) {
console.error(`π¨ [API Error ${status}]`, {
url: error.config.url,
method: error.config.method,
data: data,
headers: error.response.headers
})
}
} else if (error.request) {
// The request was made but no response was received
if (isDevelopment) {
console.error('π¨ [Network Error] No response received:', {
url: error.config?.url,
message: error.message
})
}
} else {
// Something happened in setting up the request that triggered an Error
if (isDevelopment) {
console.error('π¨ [Request Error]', error.message)
}
}
return Promise.reject(error)
}
)
export default api |