Refactor code structure for improved readability and maintainability
This commit is contained in:
165
frontend/src/api/client.ts
Normal file
165
frontend/src/api/client.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
// Función para unir clases de Tailwind
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
// Configuración base de la API
|
||||
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
|
||||
|
||||
// Interceptor para manejar errores comunes
|
||||
async function handleApiError(response: Response) {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
|
||||
// Manejar errores de autenticación
|
||||
if (response.status === 401) {
|
||||
throw new Error('No autorizado. Por favor inicia sesión.');
|
||||
}
|
||||
|
||||
// Manejar errores de validación
|
||||
if (response.status === 422) {
|
||||
const fieldErrors = errorData.errors || {};
|
||||
const errorMessage = Object.entries(fieldErrors)
|
||||
.map(([field, errors]) => `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}`)
|
||||
.join('; ');
|
||||
throw new Error(errorMessage || 'Error de validación');
|
||||
}
|
||||
|
||||
// Manejar errores de servidor
|
||||
if (response.status >= 500) {
|
||||
throw new Error('Error del servidor. Por favor intenta de nuevo más tarde.');
|
||||
}
|
||||
|
||||
// Manejar otros errores
|
||||
throw new Error(errorData.message || 'Error en la solicitud');
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// Función genérica para peticiones GET
|
||||
export async function apiGet<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
|
||||
const url = new URL(`${API_BASE_URL}${endpoint}`);
|
||||
|
||||
if (params) {
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
await handleApiError(response);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Función genérica para peticiones POST
|
||||
export async function apiPost<T>(endpoint: string, data: any): Promise<T> {
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
await handleApiError(response);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Función genérica para peticiones PUT
|
||||
export async function apiPut<T>(endpoint: string, data: any): Promise<T> {
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
await handleApiError(response);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Función genérica para peticiones DELETE
|
||||
export async function apiDelete<T>(endpoint: string): Promise<T> {
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
await handleApiError(response);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Función para subir archivos
|
||||
export async function apiUpload<T>(
|
||||
endpoint: string,
|
||||
file: File,
|
||||
additionalData?: Record<string, any>
|
||||
): Promise<T> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
if (additionalData) {
|
||||
Object.entries(additionalData).forEach(([key, value]) => {
|
||||
formData.append(key, String(value));
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
await handleApiError(response);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Función para peticiones con paginación
|
||||
export async function apiGetPaginated<T>(
|
||||
endpoint: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
filters?: Record<string, any>
|
||||
): Promise<{
|
||||
data: T[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}> {
|
||||
const params = {
|
||||
page,
|
||||
limit,
|
||||
...filters,
|
||||
};
|
||||
|
||||
return apiGet(endpoint, params);
|
||||
}
|
||||
|
||||
// Función para buscar
|
||||
export async function apiSearch<T>(
|
||||
endpoint: string,
|
||||
query: string,
|
||||
filters?: Record<string, any>
|
||||
): Promise<T[]> {
|
||||
return apiGet(endpoint, {
|
||||
search: query,
|
||||
...filters,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user