const API_BASE_URL = ''; // Relative path because of proxy interface RequestOptions extends RequestInit { headers?: Record; } async function request(url: string, options: RequestOptions = {}): Promise { const token = localStorage.getItem('token'); const defaultHeaders: Record = { ...(token ? { 'Authorization': `Bearer ${token}` } : {}), }; // Only set Content-Type to application/json if data is not FormData if (!(options.body instanceof FormData)) { defaultHeaders['Content-Type'] = 'application/json'; } const config: RequestInit = { ...options, headers: { ...defaultHeaders, ...options.headers, }, }; try { const response = await fetch(`${API_BASE_URL}${url}`, config); if (!response.ok) { if (response.status === 401) { // Handle unauthorized (e.g., redirect to login or clear store) localStorage.removeItem('token'); localStorage.removeItem('user'); // You might want to trigger a custom event or use window.location here } const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || errorData.message || `API Error: ${response.statusText}`); } // Handle empty responses (e.g. 204 No Content) if (response.status === 204) { return {} as T; } return await response.json(); } catch (error) { console.error('API Request Failed:', error); throw error; } } export const api = { get: (url: string, options?: RequestOptions) => request(url, { ...options, method: 'GET' }), post: (url: string, data: any, options?: RequestOptions) => request(url, { ...options, method: 'POST', body: data instanceof FormData ? data : JSON.stringify(data) }), put: (url: string, data: any, options?: RequestOptions) => request(url, { ...options, method: 'PUT', body: data instanceof FormData ? data : JSON.stringify(data) }), delete: (url: string, options?: RequestOptions) => request(url, { ...options, method: 'DELETE' }), patch: (url: string, data: any, options?: RequestOptions) => request(url, { ...options, method: 'PATCH', body: data instanceof FormData ? data : JSON.stringify(data) }), };