Replace HeadersInit type with Record<string, string> for headers object to allow index access with bracket notation. This resolves the TypeScript error "Property 'Authorization' does not exist on type 'HeadersInit'". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
150 lines
3.6 KiB
TypeScript
150 lines
3.6 KiB
TypeScript
import { API_BASE_URL } from '@/utils/constants';
|
|
import { getToken } from '@/utils/helpers';
|
|
|
|
export interface FetchOptions extends RequestInit {
|
|
token?: string;
|
|
}
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
public status: number,
|
|
message: string,
|
|
public data?: any
|
|
) {
|
|
super(message);
|
|
this.name = 'ApiError';
|
|
}
|
|
}
|
|
|
|
async function fetchWithAuth(
|
|
endpoint: string,
|
|
options: FetchOptions = {}
|
|
): Promise<Response> {
|
|
const token = options.token || getToken();
|
|
|
|
// Logs de debug
|
|
console.log('🔐 [API] Préparation de la requête:', {
|
|
endpoint,
|
|
hasToken: !!token,
|
|
tokenPreview: token ? `${token.substring(0, 20)}...` : 'Aucun',
|
|
});
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...options.headers as Record<string, string>,
|
|
};
|
|
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
console.log('✅ [API] Header Authorization ajouté');
|
|
} else {
|
|
console.warn('⚠️ [API] Aucun token disponible - requête sans authentification');
|
|
}
|
|
|
|
const config: RequestInit = {
|
|
...options,
|
|
headers,
|
|
};
|
|
|
|
const url = endpoint.startsWith('http') ? endpoint : `${API_BASE_URL}${endpoint}`;
|
|
|
|
console.log('📡 [API] Envoi de la requête:', {
|
|
url,
|
|
method: config.method || 'GET',
|
|
headers: headers,
|
|
body: options.body,
|
|
});
|
|
|
|
try {
|
|
const response = await fetch(url, config);
|
|
|
|
if (!response.ok) {
|
|
let errorMessage = 'Une erreur est survenue';
|
|
let errorData;
|
|
|
|
try {
|
|
errorData = await response.json();
|
|
errorMessage = errorData.message || errorData.error || errorMessage;
|
|
console.error('❌ [API] Erreur du serveur:', {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
errorData,
|
|
errorMessage,
|
|
});
|
|
} catch {
|
|
errorMessage = response.statusText || errorMessage;
|
|
console.error('❌ [API] Erreur sans JSON:', {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
});
|
|
}
|
|
|
|
throw new ApiError(response.status, errorMessage, errorData);
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
if (error instanceof ApiError) {
|
|
throw error;
|
|
}
|
|
throw new ApiError(0, 'Erreur de connexion au serveur');
|
|
}
|
|
}
|
|
|
|
export const api = {
|
|
get: async <T>(endpoint: string, options?: FetchOptions): Promise<T> => {
|
|
const response = await fetchWithAuth(endpoint, {
|
|
...options,
|
|
method: 'GET',
|
|
});
|
|
return response.json();
|
|
},
|
|
|
|
post: async <T>(
|
|
endpoint: string,
|
|
data?: any,
|
|
options?: FetchOptions
|
|
): Promise<T> => {
|
|
const response = await fetchWithAuth(endpoint, {
|
|
...options,
|
|
method: 'POST',
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
return response.json();
|
|
},
|
|
|
|
put: async <T>(
|
|
endpoint: string,
|
|
data?: any,
|
|
options?: FetchOptions
|
|
): Promise<T> => {
|
|
const response = await fetchWithAuth(endpoint, {
|
|
...options,
|
|
method: 'PUT',
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
return response.json();
|
|
},
|
|
|
|
patch: async <T>(
|
|
endpoint: string,
|
|
data?: any,
|
|
options?: FetchOptions
|
|
): Promise<T> => {
|
|
const response = await fetchWithAuth(endpoint, {
|
|
...options,
|
|
method: 'PATCH',
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
return response.json();
|
|
},
|
|
|
|
delete: async <T>(endpoint: string, options?: FetchOptions): Promise<T> => {
|
|
const response = await fetchWithAuth(endpoint, {
|
|
...options,
|
|
method: 'DELETE',
|
|
});
|
|
return response.json();
|
|
},
|
|
};
|