| |
| |
| |
| |
|
|
| class APIClient { |
| constructor(baseURL = '') { |
| this.baseURL = baseURL; |
| this.errors = []; |
| } |
|
|
| |
| |
| |
| _getFallbackData(error) { |
| |
| const safeError = error || {}; |
| |
| return { |
| data: [], |
| success: false, |
| error: true, |
| message: safeError.message || 'Failed to fetch data', |
| timestamp: Date.now(), |
| details: { |
| name: safeError.name || 'Error', |
| stack: safeError.stack || 'No stack trace available' |
| } |
| }; |
| } |
|
|
| |
| |
| |
| _logError(endpoint, method, error, duration = 0) { |
| const errorLog = { |
| endpoint: endpoint || 'unknown', |
| method: method || 'GET', |
| message: error?.message || 'Unknown error', |
| duration: duration, |
| timestamp: new Date().toISOString() |
| }; |
| |
| this.errors.push(errorLog); |
| console.error('[APIClient] Error logged:', errorLog); |
| |
| |
| if (this.errors.length > 50) { |
| this.errors = this.errors.slice(-50); |
| } |
| } |
|
|
| |
| |
| |
| async request(endpoint, options = {}) { |
| const startTime = Date.now(); |
| const method = options.method || 'GET'; |
| |
| try { |
| const url = endpoint.startsWith('http') |
| ? endpoint |
| : `${this.baseURL}${endpoint}`; |
| |
| const response = await fetch(url, { |
| ...options, |
| headers: { |
| 'Content-Type': 'application/json', |
| ...options.headers |
| } |
| }); |
|
|
| const duration = Date.now() - startTime; |
|
|
| if (!response.ok) { |
| const errorText = await response.text().catch(() => 'No error message'); |
| const error = new Error(`HTTP ${response.status}: ${errorText}`); |
| error.status = response.status; |
| error.statusText = response.statusText; |
| |
| this._logError(endpoint, method, error, duration); |
| |
| |
| return this._getFallbackData(error); |
| } |
|
|
| const data = await response.json(); |
| return data; |
|
|
| } catch (error) { |
| const duration = Date.now() - startTime; |
| |
| |
| const safeError = error || new Error('Unknown error'); |
| |
| if (safeError.name === 'AbortError') { |
| safeError.message = 'Request timeout'; |
| } else if (!safeError.message) { |
| safeError.message = 'Network error or invalid response'; |
| } |
| |
| this._logError(endpoint, method, safeError, duration); |
| |
| |
| return this._getFallbackData(safeError); |
| } |
| } |
|
|
| |
| |
| |
| async get(endpoint, options = {}) { |
| return this.request(endpoint, { ...options, method: 'GET' }); |
| } |
|
|
| |
| |
| |
| async post(endpoint, data, options = {}) { |
| return this.request(endpoint, { |
| ...options, |
| method: 'POST', |
| body: JSON.stringify(data) |
| }); |
| } |
|
|
| |
| |
| |
| async put(endpoint, data, options = {}) { |
| return this.request(endpoint, { |
| ...options, |
| method: 'PUT', |
| body: JSON.stringify(data) |
| }); |
| } |
|
|
| |
| |
| |
| async delete(endpoint, options = {}) { |
| return this.request(endpoint, { ...options, method: 'DELETE' }); |
| } |
|
|
| |
| |
| |
| getErrors() { |
| return [...this.errors]; |
| } |
|
|
| |
| |
| |
| clearErrors() { |
| this.errors = []; |
| } |
| } |
|
|
| |
| export const api = new APIClient('/api'); |
| export default api; |
|
|