Fetch API en JavaScript: Guía Completa
Publicado el 1 de octubre, 2025 • 18 min de lectura
fetch
es la forma moderna de obtener datos de servidores en JavaScript. Si necesitas cargar datos de una API, enviar información a un servidor, o subir archivos, fetch es tu herramienta principal.
¿Qué es fetch?
fetch
es una función nativa de JavaScript que te permite hacer peticiones HTTP a servidores. En otras palabras, te permite comunicarte con APIs y obtener o enviar información.
Imagina que tu aplicación es un restaurante:
- Cliente (tu app): "Quiero ver el menú"
- Mesero (fetch): Va a la cocina y trae el menú
- Cocina (servidor/API): Prepara y entrega el menú
Fetch es el mesero que va y viene entre tu aplicación y el servidor.
¿Por qué usar fetch?
Antes de fetch, usábamos XMLHttpRequest
(una API antigua y complicada):
// Forma antigua con XMLHttpRequest (NO uses esto)
const xhr = new XMLHttpRequest()
xhr.open('GET', 'https://api.ejemplo.com/usuarios')
xhr.onload = function() {
if (xhr.status === 200) {
const datos = JSON.parse(xhr.responseText)
console.log(datos)
}
}
xhr.onerror = function() {
console.error('Error')
}
xhr.send()
Complicado, ¿verdad?
Con fetch (forma moderna):
fetch('https://api.ejemplo.com/usuarios')
.then(response => response.json())
.then(datos => console.log(datos))
.catch(error => console.error('Error:', error))
Mucho más limpio y fácil de entender.
Disponibilidad
Fetch está disponible en todos los navegadores modernos y en Node.js desde la versión 18. Es el estándar actual para hacer peticiones HTTP.
Sintaxis básica de fetch
La forma más simple de usar fetch:
fetch(url)
Esto retorna una Promise (promesa) que se resuelve con la respuesta del servidor.
Ejemplo básico con async/await
async function obtenerDatos() {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
const datos = await response.json()
console.log(datos)
}
obtenerDatos()
Desglosando el código:
fetch(url)
- Hace la petición al servidorawait
- Espera a que llegue la respuestaresponse.json()
- Convierte la respuesta a formato JSON- Los datos están listos para usar
Ejemplo básico con .then()
Si prefieres usar Promises directamente:
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(datos => {
console.log(datos)
})
.catch(error => {
console.error('Error:', error)
})
Ambas formas funcionan. async/await es generalmente más fácil de leer.
El objeto Response
Cuando haces un fetch, obtienes un objeto Response
con información sobre la respuesta del servidor:
async function verificarRespuesta() {
const response = await fetch('https://api.ejemplo.com/datos')
console.log('Status:', response.status) // 200, 404, 500, etc.
console.log('OK:', response.ok) // true si status 200-299
console.log('Status Text:', response.statusText) // "OK", "Not Found", etc.
console.log('Headers:', response.headers) // Headers de la respuesta
console.log('URL:', response.url) // URL completa
}
Propiedades importantes:
Propiedad | Descripción | Ejemplo |
---|---|---|
response.ok | true si status 200-299 | true o false |
response.status | Código de estado HTTP | 200 , 404 , 500 |
response.statusText | Texto del estado | "OK", "Not Found" |
response.headers | Headers de respuesta | Objeto Headers |
response.body | Cuerpo de la respuesta | ReadableStream |
Métodos HTTP: GET, POST, PUT, DELETE
HTTP tiene diferentes "verbos" o métodos para diferentes acciones:
Método | Propósito | Analogía |
---|---|---|
GET | Obtener datos | Leer un libro |
POST | Crear datos nuevos | Escribir un libro nuevo |
PUT | Actualizar datos existentes | Editar un libro completo |
PATCH | Actualizar parte de datos | Editar una página del libro |
DELETE | Eliminar datos | Tirar el libro |
GET: Obtener datos
GET es el método por defecto de fetch. Se usa para obtener información:
// Sintaxis simple (método GET por defecto)
async function obtenerUsuarios() {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
const usuarios = await response.json()
console.log(usuarios)
}
// Sintaxis explícita
async function obtenerUsuarios() {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'GET'
})
const usuarios = await response.json()
console.log(usuarios)
}
Ejemplo real: Obtener un usuario específico
async function obtenerUsuario(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
if (!response.ok) {
throw new Error('Usuario no encontrado')
}
const usuario = await response.json()
return usuario
}
// Usar la función
obtenerUsuario(1)
.then(usuario => console.log(usuario.name))
.catch(error => console.error('Error:', error))
POST: Crear datos nuevos
POST se usa para enviar datos al servidor y crear recursos nuevos:
async function crearUsuario(datosUsuario) {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datosUsuario)
})
const usuarioCreado = await response.json()
return usuarioCreado
}
// Usar la función
const nuevoUsuario = {
name: 'Ana García',
email: 'ana@ejemplo.com',
username: 'anagarcia'
}
crearUsuario(nuevoUsuario)
.then(usuario => console.log('Usuario creado:', usuario))
.catch(error => console.error('Error:', error))
Elementos importantes de POST:
method: 'POST'
- Especifica el métodoheaders
- Le dice al servidor qué tipo de datos envíasbody
- Los datos que envías (convertidos a string con JSON.stringify)
PUT: Actualizar datos completos
PUT se usa para actualizar un recurso completo:
async function actualizarUsuario(id, datosActualizados) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datosActualizados)
})
const usuarioActualizado = await response.json()
return usuarioActualizado
}
// Usar la función
const datosActualizados = {
id: 1,
name: 'Ana García Actualizada',
email: 'ana.nueva@ejemplo.com',
username: 'anagarcia'
}
actualizarUsuario(1, datosActualizados)
.then(usuario => console.log('Usuario actualizado:', usuario))
PATCH: Actualizar datos parciales
PATCH se usa para actualizar solo algunos campos:
async function actualizarEmail(id, nuevoEmail) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: nuevoEmail // Solo actualizar el email
})
})
const usuarioActualizado = await response.json()
return usuarioActualizado
}
// Usar la función
actualizarEmail(1, 'nuevo@ejemplo.com')
.then(usuario => console.log('Email actualizado:', usuario))
Diferencia entre PUT y PATCH:
- PUT: Reemplaza el recurso completo (debes enviar todos los campos)
- PATCH: Actualiza solo los campos que especifiques
DELETE: Eliminar datos
DELETE se usa para eliminar recursos:
async function eliminarUsuario(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'DELETE'
})
if (response.ok) {
console.log('Usuario eliminado exitosamente')
}
}
// Usar la función
eliminarUsuario(1)
.then(() => console.log('Usuario eliminado'))
.catch(error => console.error('Error:', error))
Headers (Encabezados)
Los headers son información adicional que envías con tu petición. Piénsalos como el sobre de una carta que contiene datos sobre el remitente, destinatario, etc.
Headers comunes
const response = await fetch('https://api.ejemplo.com/datos', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // Tipo de datos que envías
'Accept': 'application/json', // Tipo de datos que aceptas
'Authorization': 'Bearer tu-token-aqui', // Token de autenticación
'X-Custom-Header': 'valor-personalizado' // Header personalizado
},
body: JSON.stringify({ dato: 'valor' })
})
Headers más usados:
Header | Propósito | Ejemplo |
---|---|---|
Content-Type | Tipo de datos que envías | application/json |
Accept | Tipo de datos que aceptas | application/json |
Authorization | Token de autenticación | Bearer abc123... |
User-Agent | Información del navegador | Mozilla/5.0... |
Leer headers de la respuesta
async function verHeaders() {
const response = await fetch('https://api.ejemplo.com/datos')
// Obtener un header específico
const contentType = response.headers.get('content-type')
console.log('Content-Type:', contentType)
// Iterar sobre todos los headers
response.headers.forEach((valor, nombre) => {
console.log(`${nombre}: ${valor}`)
})
}
Diferentes tipos de datos
JSON (lo más común)
async function enviarJSON() {
const response = await fetch('https://api.ejemplo.com/usuarios', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nombre: 'Ana',
edad: 25
})
})
const datos = await response.json()
console.log(datos)
}
Texto plano
async function obtenerTexto() {
const response = await fetch('https://ejemplo.com/archivo.txt')
const texto = await response.text()
console.log(texto)
}
FormData (para formularios y archivos)
async function subirArchivo(archivo) {
const formData = new FormData()
formData.append('archivo', archivo)
formData.append('descripcion', 'Mi archivo')
const response = await fetch('https://api.ejemplo.com/upload', {
method: 'POST',
body: formData // NO pongas Content-Type, se añade automáticamente
})
const resultado = await response.json()
console.log(resultado)
}
// Usar con un input de archivo
const input = document.querySelector('input[type="file"]')
input.addEventListener('change', (e) => {
const archivo = e.target.files[0]
subirArchivo(archivo)
})
Blob (para imágenes, videos, etc.)
async function descargarImagen() {
const response = await fetch('https://ejemplo.com/imagen.jpg')
const blob = await response.blob()
// Crear URL temporal para la imagen
const url = URL.createObjectURL(blob)
// Mostrar la imagen
const img = document.createElement('img')
img.src = url
document.body.appendChild(img)
}
Manejo de errores
Fetch tiene una peculiaridad: solo rechaza la promesa en errores de red. Si el servidor responde con error 404 o 500, fetch NO lo considera error.
Verificar response.ok
async function obtenerDatos() {
try {
const response = await fetch('https://api.ejemplo.com/datos')
// Verificar si la respuesta fue exitosa
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const datos = await response.json()
return datos
} catch (error) {
console.error('Error:', error.message)
throw error
}
}
Manejo completo de errores
async function obtenerUsuario(id) {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
// Error 404, 500, etc.
if (!response.ok) {
if (response.status === 404) {
throw new Error('Usuario no encontrado')
} else if (response.status === 500) {
throw new Error('Error del servidor')
} else {
throw new Error(`Error: ${response.status}`)
}
}
const usuario = await response.json()
return usuario
} catch (error) {
// Errores de red (sin internet, servidor caído, etc.)
if (error instanceof TypeError) {
console.error('Error de red:', error.message)
throw new Error('No se pudo conectar al servidor')
}
// Otros errores
console.error('Error:', error.message)
throw error
}
}
// Usar la función
obtenerUsuario(999)
.then(usuario => console.log(usuario))
.catch(error => console.error('Falló:', error.message))
Fetch no rechaza en errores HTTP
A diferencia de otras librerías, fetch solo rechaza la promesa en errores de red (sin internet, DNS falló, etc.). Respuestas con status 404, 500, etc. se consideran "exitosas" y debes verificar response.ok
manualmente.
Opciones de configuración
Fetch acepta un segundo parámetro con opciones:
const response = await fetch(url, {
method: 'GET', // GET, POST, PUT, DELETE, etc.
headers: {}, // Headers personalizados
body: null, // Datos a enviar (no en GET)
mode: 'cors', // cors, no-cors, same-origin
credentials: 'include', // omit, same-origin, include
cache: 'default', // default, no-cache, reload, force-cache
redirect: 'follow', // follow, error, manual
referrer: 'client', // URL del referrer
signal: null // AbortSignal para cancelar
})
Opciones comunes explicadas
mode:
// cors: Permite peticiones a otros dominios (lo más común)
fetch('https://api.ejemplo.com/datos', {
mode: 'cors'
})
// same-origin: Solo permite peticiones al mismo dominio
fetch('/api/datos', {
mode: 'same-origin'
})
credentials:
// include: Envía cookies incluso a otros dominios
fetch('https://api.ejemplo.com/datos', {
credentials: 'include'
})
// same-origin: Solo envía cookies al mismo dominio (default)
fetch('/api/datos', {
credentials: 'same-origin'
})
// omit: No envía cookies
fetch('https://api.ejemplo.com/datos', {
credentials: 'omit'
})
cache:
// no-cache: Siempre pide datos frescos
fetch('https://api.ejemplo.com/datos', {
cache: 'no-cache'
})
// force-cache: Usa caché si está disponible
fetch('https://api.ejemplo.com/datos', {
cache: 'force-cache'
})
Cancelar peticiones con AbortController
A veces necesitas cancelar una petición (usuario cambia de página, timeout, etc.):
async function buscarConTimeout() {
// Crear un controlador para cancelar
const controller = new AbortController()
const signal = controller.signal
// Cancelar después de 5 segundos
const timeout = setTimeout(() => controller.abort(), 5000)
try {
const response = await fetch('https://api.ejemplo.com/datos', {
signal: signal // Pasar el signal
})
clearTimeout(timeout) // Cancelar el timeout si termina a tiempo
const datos = await response.json()
return datos
} catch (error) {
if (error.name === 'AbortError') {
console.log('Petición cancelada')
} else {
console.error('Error:', error)
}
}
}
Ejemplo práctico: Búsqueda con cancelación
let controladorActual = null
async function buscar(query) {
// Cancelar búsqueda anterior si existe
if (controladorActual) {
controladorActual.abort()
}
// Crear nuevo controlador
controladorActual = new AbortController()
try {
const response = await fetch(`/api/buscar?q=${query}`, {
signal: controladorActual.signal
})
const resultados = await response.json()
mostrarResultados(resultados)
} catch (error) {
if (error.name === 'AbortError') {
console.log('Búsqueda cancelada')
}
}
}
// En un input de búsqueda
input.addEventListener('input', (e) => {
buscar(e.target.value)
})
Esto cancela búsquedas anteriores si el usuario sigue escribiendo.
Ejemplos prácticos completos
Ejemplo 1: Cargar y mostrar lista de usuarios
async function cargarUsuarios() {
const contenedor = document.getElementById('usuarios')
contenedor.innerHTML = '<p>Cargando...</p>'
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
if (!response.ok) {
throw new Error('Error al cargar usuarios')
}
const usuarios = await response.json()
// Limpiar contenedor
contenedor.innerHTML = ''
// Crear HTML para cada usuario
usuarios.forEach(usuario => {
const div = document.createElement('div')
div.innerHTML = `
<h3>${usuario.name}</h3>
<p>Email: ${usuario.email}</p>
<p>Ciudad: ${usuario.address.city}</p>
<hr>
`
contenedor.appendChild(div)
})
} catch (error) {
contenedor.innerHTML = `<p>Error: ${error.message}</p>`
}
}
// Llamar al cargar la página
cargarUsuarios()
Ejemplo 2: Formulario de contacto
async function enviarFormulario(evento) {
evento.preventDefault()
// Obtener datos del formulario
const formulario = evento.target
const datos = {
nombre: formulario.nombre.value,
email: formulario.email.value,
mensaje: formulario.mensaje.value
}
// Deshabilitar botón mientras envía
const boton = formulario.querySelector('button')
boton.disabled = true
boton.textContent = 'Enviando...'
try {
const response = await fetch('/api/contacto', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datos)
})
if (!response.ok) {
throw new Error('Error al enviar mensaje')
}
const resultado = await response.json()
alert('Mensaje enviado exitosamente')
formulario.reset()
} catch (error) {
alert('Error: ' + error.message)
} finally {
boton.disabled = false
boton.textContent = 'Enviar'
}
}
// Conectar con el formulario
document.getElementById('formulario-contacto')
.addEventListener('submit', enviarFormulario)
Ejemplo 3: Subir imagen con preview
async function subirImagen(archivo) {
// Mostrar preview
const preview = document.getElementById('preview')
const reader = new FileReader()
reader.onload = (e) => {
preview.src = e.target.result
}
reader.readAsDataURL(archivo)
// Preparar FormData
const formData = new FormData()
formData.append('imagen', archivo)
formData.append('titulo', 'Mi imagen')
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
})
if (!response.ok) {
throw new Error('Error al subir imagen')
}
const resultado = await response.json()
console.log('Imagen subida:', resultado.url)
alert('Imagen subida exitosamente')
} catch (error) {
alert('Error: ' + error.message)
}
}
// Conectar con input file
document.getElementById('input-imagen')
.addEventListener('change', (e) => {
const archivo = e.target.files[0]
if (archivo) {
subirImagen(archivo)
}
})
Ejemplo 4: CRUD completo
// CRUD = Create, Read, Update, Delete
const API_URL = 'https://jsonplaceholder.typicode.com/users'
// CREATE - Crear usuario
async function crearUsuario(datos) {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(datos)
})
return await response.json()
}
// READ - Leer usuarios
async function obtenerUsuarios() {
const response = await fetch(API_URL)
return await response.json()
}
// READ - Leer un usuario
async function obtenerUsuario(id) {
const response = await fetch(`${API_URL}/${id}`)
return await response.json()
}
// UPDATE - Actualizar usuario
async function actualizarUsuario(id, datos) {
const response = await fetch(`${API_URL}/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(datos)
})
return await response.json()
}
// DELETE - Eliminar usuario
async function eliminarUsuario(id) {
const response = await fetch(`${API_URL}/${id}`, {
method: 'DELETE'
})
return response.ok
}
// Usar las funciones
async function ejemploCRUD() {
// Crear
const nuevoUsuario = await crearUsuario({
name: 'Ana García',
email: 'ana@ejemplo.com'
})
console.log('Usuario creado:', nuevoUsuario)
// Leer todos
const usuarios = await obtenerUsuarios()
console.log('Usuarios:', usuarios.length)
// Leer uno
const usuario = await obtenerUsuario(1)
console.log('Usuario 1:', usuario.name)
// Actualizar
const actualizado = await actualizarUsuario(1, {
name: 'Ana García Actualizada',
email: 'ana.nueva@ejemplo.com'
})
console.log('Usuario actualizado:', actualizado)
// Eliminar
const eliminado = await eliminarUsuario(1)
console.log('Usuario eliminado:', eliminado)
}
Patrones útiles
Patrón 1: Función wrapper reutilizable
async function fetchJSON(url, opciones = {}) {
try {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
...opciones.headers
},
...opciones
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json()
} catch (error) {
console.error('Error en fetch:', error)
throw error
}
}
// Usar la función wrapper
const usuarios = await fetchJSON('https://api.ejemplo.com/usuarios')
const usuario = await fetchJSON('https://api.ejemplo.com/usuarios/1')
Patrón 2: Retry automático
async function fetchConReintentos(url, opciones = {}, intentos = 3) {
for (let i = 0; i < intentos; i++) {
try {
const response = await fetch(url, opciones)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json()
} catch (error) {
// Si es el último intento, lanzar el error
if (i === intentos - 1) throw error
// Esperar antes de reintentar (backoff exponencial)
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
}
}
}
// Usar con reintentos
const datos = await fetchConReintentos('https://api.ejemplo.com/datos', {}, 3)
Patrón 3: Cache simple
const cache = new Map()
async function fetchConCache(url, tiempoCache = 60000) {
// Verificar si está en caché y no ha expirado
if (cache.has(url)) {
const { datos, timestamp } = cache.get(url)
if (Date.now() - timestamp < tiempoCache) {
console.log('Usando caché')
return datos
}
}
// Hacer fetch y guardar en caché
console.log('Haciendo fetch')
const response = await fetch(url)
const datos = await response.json()
cache.set(url, {
datos,
timestamp: Date.now()
})
return datos
}
// Primera llamada: hace fetch
const datos1 = await fetchConCache('https://api.ejemplo.com/datos')
// Segunda llamada (dentro de 60s): usa caché
const datos2 = await fetchConCache('https://api.ejemplo.com/datos')
Patrón 4: Progreso de descarga
async function descargarConProgreso(url) {
const response = await fetch(url)
const total = response.headers.get('content-length')
let descargado = 0
const chunks = []
const reader = response.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
chunks.push(value)
descargado += value.length
// Calcular progreso
const progreso = total ? (descargado / total) * 100 : 0
console.log(`Descargado: ${progreso.toFixed(2)}%`)
}
// Combinar todos los chunks
const blob = new Blob(chunks)
return blob
}
// Usar con una imagen
descargarConProgreso('https://ejemplo.com/imagen-grande.jpg')
.then(blob => {
const url = URL.createObjectURL(blob)
console.log('Descarga completa:', url)
})
Errores comunes
Error 1: Olvidar await en .json()
// ❌ Incorrecto
async function obtenerDatos() {
const response = await fetch('url')
const datos = response.json() // Falta await
console.log(datos) // Imprime una Promise, no los datos
}
// ✓ Correcto
async function obtenerDatos() {
const response = await fetch('url')
const datos = await response.json()
console.log(datos)
}
Error 2: No verificar response.ok
// ❌ Incorrecto
async function obtenerDatos() {
const response = await fetch('url')
const datos = await response.json()
return datos
}
// ✓ Correcto
async function obtenerDatos() {
const response = await fetch('url')
if (!response.ok) {
throw new Error('Error en la petición')
}
const datos = await response.json()
return datos
}
Error 3: Enviar body en GET
// ❌ Incorrecto: GET no debe tener body
fetch('url', {
method: 'GET',
body: JSON.stringify({ dato: 'valor' })
})
// ✓ Correcto: Usa query parameters
fetch('url?dato=valor', {
method: 'GET'
})
Error 4: Olvidar Content-Type en POST
// ❌ Incorrecto
fetch('url', {
method: 'POST',
body: JSON.stringify({ dato: 'valor' })
// Falta Content-Type header
})
// ✓ Correcto
fetch('url', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ dato: 'valor' })
})
Error 5: Usar .json() en respuestas no-JSON
// ❌ Incorrecto: Si la respuesta es texto plano
async function obtenerTexto() {
const response = await fetch('archivo.txt')
const datos = await response.json() // Error: no es JSON
}
// ✓ Correcto
async function obtenerTexto() {
const response = await fetch('archivo.txt')
const texto = await response.text() // Usar .text() para texto plano
}
Fetch en diferentes entornos
En Node.js
Fetch está disponible nativamente desde Node.js 18:
// Node.js 18+
const response = await fetch('https://api.ejemplo.com/datos')
const datos = await response.json()
Para versiones anteriores, instala node-fetch:
npm install node-fetch
// Node.js < 18
import fetch from 'node-fetch'
const response = await fetch('https://api.ejemplo.com/datos')
const datos = await response.json()
En NextJS (Server Components)
// app/page.tsx (Server Component)
export default async function Page() {
const response = await fetch('https://api.ejemplo.com/productos')
const productos = await response.json()
return (
<div>
{productos.map(p => (
<div key={p.id}>{p.nombre}</div>
))}
</div>
)
}
En React (Client Components)
'use client'
import { useState, useEffect } from 'react'
export default function Productos() {
const [productos, setProductos] = useState([])
const [cargando, setCargando] = useState(true)
useEffect(() => {
async function cargar() {
const response = await fetch('https://api.ejemplo.com/productos')
const datos = await response.json()
setProductos(datos)
setCargando(false)
}
cargar()
}, [])
if (cargando) return <div>Cargando...</div>
return (
<div>
{productos.map(p => (
<div key={p.id}>{p.nombre}</div>
))}
</div>
)
}
Resumen
Puntos clave sobre Fetch:
- Fetch es la forma moderna de hacer peticiones HTTP
- Retorna una Promise que se resuelve con un objeto Response
- Debes llamar
.json()
,.text()
, o.blob()
para obtener los datos - Siempre verifica
response.ok
- fetch no rechaza en errores HTTP - Usa
method
para especificar GET, POST, PUT, DELETE - Usa
headers
para enviar información adicional - Usa
body
para enviar datos (no en GET) - Siempre maneja errores con try/catch
- Puedes cancelar peticiones con AbortController
- Funciona en navegadores y Node.js 18+
Tabla de referencia rápida:
Acción | Código |
---|---|
GET básico | fetch(url) |
POST con JSON | fetch(url, { method: 'POST', body: JSON.stringify(data) }) |
Obtener JSON | await response.json() |
Obtener texto | await response.text() |
Verificar éxito | if (!response.ok) throw new Error() |
Con headers | fetch(url, { headers: { 'Authorization': 'Bearer token' } }) |
Cancelar | fetch(url, { signal: controller.signal }) |
En el próximo artículo veremos Axios, una alternativa popular a fetch con funcionalidades adicionales.
Recursos adicionales:
Sobre el autor: Desarrollador especializado en JavaScript, React y NextJS. Creo contenido educativo en español para ayudar a la comunidad de desarrolladores.