Skip to content

L54 - Fetch API

fetch() es una API nativa del navegador (y disponible en Node.js desde v18+) para realizar peticiones HTTP. Devuelve una Promise que se resuelve con un objeto Response. Es la forma moderna y estándar de hacer peticiones AJAX, reemplazando a XMLHttpRequest.

fetch('https://api.ejemplo.com/usuarios')
.then(response => {
// Response no es el JSON, es un objeto con metadatos
return response.json(); // devuelve otra Promise
})
.then(usuarios => {
console.log(usuarios);
})
.catch(error => {
console.error('Error de red:', error);
});

Con async/await:

async function obtenerUsuarios() {
const response = await fetch('https://api.ejemplo.com/usuarios');
const usuarios = await response.json();
return usuarios;
}
fetch('/api/datos')
.then(res => {
console.log(res.status); // 200, 404, 500...
console.log(res.statusText); // 'OK', 'Not Found'...
console.log(res.ok); // true si status 200-299
console.log(res.headers); // Headers de la respuesta
console.log(res.url); // URL final (tras redirecciones)
});
MétodoUso
res.json()Parsa como JSON
res.text()Devuelve texto plano
res.blob()Para binarios (imágenes, archivos)
res.formData()Para datos de formulario
res.arrayBuffer()Para buffers binarios

Cuidado: fetch solo rechaza la Promise en caso de error de red (sin conexión, DNS falla, timeout). Un código HTTP 404 o 500 NO rechaza la Promise:

// Esto NO funciona como esperas
fetch('/api/no-existe')
.then(res => res.json())
.catch(err => {
// Solo si hay error de red
});

La solución es verificar response.ok:

async function fetchSeguro(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}
return res.json();
}
try {
const datos = await fetchSeguro('/api/no-existe');
} catch (err) {
console.error('Petición falló:', err.message);
}

Para enviar datos al servidor:

const usuario = {
nombre: 'Ana',
email: 'ana@ejemplo.com'
};
const response = await fetch('/api/usuarios', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify(usuario)
});
if (!response.ok) {
throw new Error(`Error ${response.status}`);
}
const resultado = await response.json();
console.log('Usuario creado:', resultado);
// PUT (actualizar)
fetch('/api/usuarios/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nombre: 'Ana Updated' })
});
// DELETE
fetch('/api/usuarios/1', { method: 'DELETE' });
// PATCH (actualización parcial)
fetch('/api/usuarios/1', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nombre: 'Ana Patch' })
});

📝 Enviar FormData (formularios, archivos)

Section titled “📝 Enviar FormData (formularios, archivos)”
const formData = new FormData();
formData.append('nombre', 'Ana');
formData.append('avatar', archivoInput.files[0]);
const response = await fetch('/api/usuarios', {
method: 'POST',
body: formData // No pongas Content-Type, fetch lo pone solo
});
const response = await fetch(url, {
method: 'GET', // o POST, PUT, DELETE...
headers: { ... },
body: ...,
signal: AbortSignal.timeout(5000), // timeout 5s
cache: 'no-cache', // no-store, reload, force-cache...
credentials: 'include', // enviar cookies cross-origin
mode: 'cors', // same-origin, no-cors
redirect: 'follow' // manual, error
});
const controller = new AbortController();
// Cancelar después de 3s
setTimeout(() => controller.abort(), 3000);
try {
const res = await fetch(url, { signal: controller.signal });
} catch (err) {
if (err.name === 'AbortError') {
console.log('Petición cancelada');
}
}
  1. Olvidar await en res.json(): res.json() devuelve una Promise.
  2. No verificar response.ok: los 404/500 pasan desapercibidos.
  3. Usar fetch con URLs relativas mal formadas: asegúrate de que la ruta sea correcta.
  4. Olvidar JSON.stringify() en el body: el body debe ser un string, no un objeto.

🎯 Regla de oro: siempre envuelve fetch en una función que verifique response.ok y maneje errores de red + HTTP por separado.