import { ValidationError, ErrorService } from './errorService'; export class ApiError extends Error { public validationErrors: ValidationError[]; public statusCode: number; public originalError?: any; constructor(message: string, validationErrors: ValidationError[] = [], statusCode: number = 0, originalError?: any) { super(message); this.name = 'ApiError'; this.validationErrors = validationErrors; this.statusCode = statusCode; this.originalError = originalError; } } export class ApiClient { private baseURL: string; constructor() { this.baseURL = import.meta.env.VITE_API_URL || '/api'; } private getAuthHeaders(): HeadersInit { const token = localStorage.getItem('token'); return token ? { 'Authorization': `Bearer ${token}` } : {}; } private async handleApiResponse(response: Response): Promise { if (!response.ok) { let errorData; try { // Try to parse error response as JSON const responseText = await response.text(); errorData = responseText ? JSON.parse(responseText) : {}; } catch { // If not JSON, create a generic error object errorData = { error: `HTTP ${response.status}: ${response.statusText}` }; } // Extract validation errors using your existing ErrorService const validationErrors = ErrorService.extractValidationErrors(errorData); if (validationErrors.length > 0) { // Throw error with validationErrors property for useBackendValidation hook throw new ApiError( errorData.error || 'Validation failed', validationErrors, response.status, errorData ); } // Throw regular error for non-validation errors throw new ApiError( errorData.error || errorData.message || `HTTP error! status: ${response.status}`, [], response.status, errorData ); } // For successful responses, try to parse as JSON try { const responseText = await response.text(); return responseText ? JSON.parse(responseText) : {} as T; } catch (error) { // If response is not JSON but request succeeded (e.g., 204 No Content) return {} as T; } } async request(endpoint: string, options: RequestInit = {}): Promise { const url = `${this.baseURL}${endpoint}`; const config: RequestInit = { headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders(), ...options.headers, }, ...options, }; try { const response = await fetch(url, config); return await this.handleApiResponse(response); } catch (error) { // Re-throw the error to be caught by useBackendValidation if (error instanceof ApiError) { throw error; } // Wrap non-ApiError errors throw new ApiError( error instanceof Error ? error.message : 'Unknown error occurred', [], 0, error ); } } // Standardized HTTP methods get = (endpoint: string) => this.request(endpoint); post = (endpoint: string, data?: any) => this.request(endpoint, { method: 'POST', body: data ? JSON.stringify(data) : undefined }); put = (endpoint: string, data?: any) => this.request(endpoint, { method: 'PUT', body: data ? JSON.stringify(data) : undefined }); patch = (endpoint: string, data?: any) => this.request(endpoint, { method: 'PATCH', body: data ? JSON.stringify(data) : undefined }); delete = (endpoint: string) => this.request(endpoint, { method: 'DELETE' }); } export const apiClient = new ApiClient();