Fetch API: Guía Completa para Peticiones HTTP en JavaScript
Todo lo que necesitas saber para consumir APIs de forma moderna, segura y eficiente usando la Fetch API.
¿Qué es Fetch API?
Fetch API es una interfaz nativa de JavaScript basada en promesas que permite realizar peticiones HTTP de forma declarativa. Reemplaza a XMLHttpRequest con una sintaxis más limpia y soporte nativo de async/await.
Principales ventajas:
- API basada en promesas – fácil manejo de asincronía.
- Soporte integrado en todos los navegadores modernos y en entornos Node.js (a partir de la versión 18).
- Flexibilidad para configurar cabeceras, cuerpos, credenciales y modos de caché.
Uso básico de Fetch
El siguiente ejemplo muestra una petición GET a una API pública.
fetch('https://api.publicapis.org/entries')
.then(response => {
if (!response.ok) {
throw new Error(`Error HTTP: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(err => console.error('Fetch error:', err));
Con async/await la misma lógica se vuelve más legible:
async function loadApis() {
try {
const response = await fetch('https://api.publicapis.org/entries');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const result = await response.json();
console.log(result);
} catch (e) {
console.error('Error:', e);
}
}
loadApis();
Opciones avanzadas y verbos HTTP
Fetch acepta un segundo parámetro init con configuraciones como método, cabeceras, cuerpo y credenciales.
const payload = { username: 'john', password: 'secret' };
fetch('https://example.com/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(payload),
credentials: 'include' // envía cookies de sesión
})
.then(res => res.json())
.then(data => console.log('Login ok:', data))
.catch(err => console.error('Login failed:', err));
Ejemplo de PUT con FormData (útil para subir archivos):
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('description', 'Foto de perfil');
fetch('/api/upload', {
method: 'PUT',
body: form,
// No es necesario establecer Content-Type; el navegador lo gestiona
})
.then(r => r.json())
.then(r => console.log('Upload success', r))
.catch(e => console.error('Upload error', e));
Fetch vs. Axios vs. XMLHttpRequest
Ventajas de Fetch
- Sin dependencias externas.
- Basado en promesas nativas.
- Mejor integración con Service Workers y Streams.
Cuándo usar Axios
- Necesitas interceptores de request/response.
- Compatibilidad con navegadores antiguos (IE 11) sin polyfills.
- Soporte automático de transformación de JSON.
| Característica | Fetch API | Axios | XMLHttpRequest |
|---|---|---|---|
| Basado en promesas | Sí | Sí | No (callback) |
| Cancelación de petición | AbortController | CancelToken (legacy) | Abort() |
| Soporte de streaming | Sí (ReadableStream) | No | No |
| Tamaño del bundle | 0 KB (nativo) | ≈ 15 KB (npm) | 0 KB (nativo) |
Seguridad, CORS y Credenciales
Cross‑Origin Resource Sharing (CORS) controla qué dominios pueden consumir tu API. Con Fetch, puedes definir el modo de la solicitud:
mode: 'cors'– permite peticiones cross‑origin con cabeceras CORS válidas.mode: 'no-cors'– solo permite solicitudes simples; la respuesta es opaque.mode: 'same-origin'– bloquea cualquier dominio externo.
Ejemplo de petición con credenciales (cookies, HTTP auth):
fetch('https://api.secure.com/user', {
credentials: 'include', // envía cookies de origen cruzado
mode: 'cors'
})
.then(r => r.json())
.then(user => console.log(user));
En el servidor (Node/Express) habilitar CORS:
const cors = require('cors');
app.use(cors({
origin: 'https://mi-frontend.com',
credentials: true
}));
Consejo de seguridad: nunca confíes en datos enviados por el cliente. Valida y sanitiza siempre en el backend.
Rendimiento, caché y streaming
Fetch permite controlar el comportamiento de caché mediante la opción cache:
default– comportamiento estándar del navegador.no-store– nunca almacena en caché.reload– fuerza una petición al servidor.force-cache– usa la caché si está disponible.only-if-cached– solo responde con datos en caché (requieremode: 'same-origin').
Ejemplo de streaming de un archivo grande:
fetch('/large-file.zip')
.then(res => {
const reader = res.body.getReader();
const chunks = [];
function pump() {
return reader.read().then(({done, value}) => {
if (done) {
const blob = new Blob(chunks);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = 'large-file.zip'; a.click();
return;
}
chunks.push(value);
return pump();
});
}
return pump();
})
.catch(err => console.error('Streaming error', err));
Utilizar AbortController para cancelar peticiones largas:
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000); // 5 s
fetch('/slow-endpoint', { signal: controller.signal })
.then(r => r.text())
.then(txt => console.log(txt))
.catch(e => {
if (e.name === 'AbortError') console.warn('Petición abortada');
else console.error(e);
})
.finally(() => clearTimeout(timeout));
Diagnóstico de errores comunes
- NetworkError cuando la URL es incorrecta: verifica la ruta y el protocolo (http vs https).
- Respuesta opaque (no‑cors): sólo puedes leer
statusytype. Cambia acorso usa un proxy. - CORS 403: el servidor debe incluir
Access-Control-Allow-Origincon tu dominio. - JSON parse error: asegúrate de que la respuesta tenga
Content-Type: application/jsono usaresponse.text()primero.
Herramientas recomendadas:
- Chrome DevTools → Network tab (ver encabezados de petición/respuesta).
- Postman o Insomnia para probar la API fuera del navegador.
- cURL con la opción
-vpara inspeccionar la negociación TLS y CORS.
Mejores prácticas al usar Fetch
- Siempre verifica
response.okantes de procesar el cuerpo. - Usa
AbortControllerpara evitar peticiones colgantes. - Centraliza la lógica de manejo de errores en una función reutilizable.
- Encapsula peticiones en un módulo o servicio (por ejemplo,
api.js) para mantener el código DRY. - Configura timeout manual (Fetch no incluye timeout nativo).
- Aplica políticas de reintento exponencial en caso de fallos transitorios.
- Limita la exposición de datos sensibles en encabezados; usa HTTPS siempre.
- Documenta la API (OpenAPI/Swagger) y genera tipos TypeScript para mayor seguridad.
Ejemplo de wrapper reutilizable:
// api.js
export async function request(url, options = {}, timeout = 8000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const config = { ...options, signal: controller.signal };
try {
const resp = await fetch(url, config);
clearTimeout(id);
if (!resp.ok) {
const err = await resp.text();
throw new Error(`HTTP ${resp.status}: ${err}`);
}
return resp.json();
} catch (e) {
if (e.name === 'AbortError') throw new Error('Request timed out');
throw e;
}
}
// usage
import { request } from './api.js';
request('https://api.example.com/data')
.then(d => console.log(d))
.catch(err => console.error(err));
Fetch API: Guía Completa para Realizar Peticiones HTTP con JavaScript