Fetch API y Manejo de APIs
Fetch API y Manejo de APIs Fundamental
Section titled “Fetch API y Manejo de APIs ”Peticiones básicas Básico
Section titled “Peticiones básicas ”// Petición GET simplefetch('https://api.ejemplo.com/datos') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));
// Con async/awaitasync function obtenerDatos() { try { const response = await fetch('https://api.ejemplo.com/datos'); const data = await response.json(); return data; } catch (error) { console.error('Error:', error); throw error; }}// Petición POST con datosconst datos = { nombre: 'Juan', edad: 25};
fetch('https://api.ejemplo.com/usuarios', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(datos)}) .then(response => response.json()) .then(data => console.log('Success:', data)) .catch(error => console.error('Error:', error));Opciones de configuración Importante
Section titled “Opciones de configuración ”Headers y opciones
Section titled “Headers y opciones”const opciones = { method: 'POST', // GET, POST, PUT, DELETE, etc. headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer tu-token-aqui', 'Accept': 'application/json' }, body: JSON.stringify(datos), mode: 'cors', // no-cors, cors, same-origin cache: 'no-cache', // default, no-cache, reload, force-cache credentials: 'same-origin', // include, same-origin, omit redirect: 'follow', // manual, follow, error referrerPolicy: 'no-referrer' // no-referrer, origin, same-origin};
fetch('https://api.ejemplo.com/endpoint', opciones);Manejo de respuestas Importante
Section titled “Manejo de respuestas ”Verificación de estado
Section titled “Verificación de estado”async function hacerPeticion(url) { try { const response = await fetch(url);
// Verificar si la petición fue exitosa if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }
// Verificar el tipo de contenido const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new TypeError('La respuesta no es JSON'); }
return await response.json(); } catch (error) { console.error('Error:', error); throw error; }}Diferentes tipos de respuesta
Section titled “Diferentes tipos de respuesta”// JSONconst jsonData = await response.json();
// Texto planoconst texto = await response.text();
// Blob (archivos)const blob = await response.blob();
// FormDataconst formData = await response.formData();
// ArrayBufferconst arrayBuffer = await response.arrayBuffer();Cliente API reutilizable Avanzado
Section titled “Cliente API reutilizable ”Clase APIClient
Section titled “Clase APIClient”class APIClient { constructor(baseURL) { this.baseURL = baseURL; }
async request(endpoint, options = {}) { const url = `${this.baseURL}${endpoint}`; const headers = { 'Content-Type': 'application/json', ...options.headers };
try { const response = await fetch(url, { ...options, headers });
if (!response.ok) { throw new APIError( 'Error en la petición', response.status, await response.text() ); }
return await response.json(); } catch (error) { if (error instanceof APIError) { throw error; } throw new APIError('Error de red', 0, error.message); } }
// Métodos de conveniencia 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' }); }}
// Usoconst api = new APIClient('https://api.ejemplo.com');
// GETconst usuarios = await api.get('/usuarios');
// POSTconst nuevoUsuario = await api.post('/usuarios', { nombre: 'Juan', edad: 25});Interceptores y middleware Avanzado
Section titled “Interceptores y middleware ”Implementación de interceptores
Section titled “Implementación de interceptores”class APIClientConInterceptores { constructor() { this.interceptors = { request: [], response: [] }; }
addRequestInterceptor(interceptor) { this.interceptors.request.push(interceptor); }
addResponseInterceptor(interceptor) { this.interceptors.response.push(interceptor); }
async fetch(url, options = {}) { let config = { url, ...options };
// Aplicar interceptores de petición for (const interceptor of this.interceptors.request) { config = await interceptor(config); }
try { let response = await fetch(config.url, config);
// Aplicar interceptores de respuesta for (const interceptor of this.interceptors.response) { response = await interceptor(response); }
return response; } catch (error) { throw error; } }}
// Usoconst client = new APIClientConInterceptores();
// Agregar token de autenticaciónclient.addRequestInterceptor(async (config) => { config.headers = { ...config.headers, 'Authorization': `Bearer ${await getToken()}` }; return config;});
// Manejar erroresclient.addResponseInterceptor(async (response) => { if (!response.ok) { if (response.status === 401) { // Renovar token y reintentar await renovarToken(); } throw new Error('Error en la petición'); } return response;});Mejores prácticas Recomendado
Section titled “Mejores prácticas ”Manejo de errores
Section titled “Manejo de errores”// ❌ Malofetch(url).then(res => res.json());
// ✅ Buenoasync function fetchConManejo(url) { try { const response = await fetch(url);
if (!response.ok) { throw new HTTPError(response.status, response.statusText); }
const data = await response.json(); return data; } catch (error) { if (error instanceof HTTPError) { // Manejar errores HTTP manejarErrorHTTP(error); } else { // Manejar errores de red manejarErrorRed(error); } throw error; }}Cancelación de peticiones
Section titled “Cancelación de peticiones”function fetchConTimeout(url, timeout = 5000) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal }) .then(response => response.json()) .catch(error => { if (error.name === 'AbortError') { throw new Error('Petición cancelada por timeout'); } throw error; }) .finally(() => clearTimeout(timeoutId));}Cache y reintento
Section titled “Cache y reintento”class APIClientConCache { constructor() { this.cache = new Map(); }
async fetchConCache(url, options = {}) { const cacheKey = `${url}-${JSON.stringify(options)}`;
if (this.cache.has(cacheKey)) { return this.cache.get(cacheKey); }
const response = await this.fetchConReintento(url, options); this.cache.set(cacheKey, response);
return response; }
async fetchConReintento(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fetch(url, options); } catch (error) { if (i === maxRetries - 1) throw error; await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i))); } } }}
🐝