Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

  1. Inicio
  2. Blog
  3. Desarrollo de software

Desarrollo de software

Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

Fetch es la forma integrada de llamar a API desde JavaScript, pero tiene una sorpresa que sorprende a casi todos. Aprenda a enviar solicitudes, manejar todo tipo de fallas y crear un pequeño asistente que pueda reutilizar.

9 min de lectura
Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

Puntos clave

  • fetch() devuelve una promesa para Response y leer el cuerpo lleva un segundo await.
  • Los errores HTTP como 404 y 500 no rechazan, así que siempre verifique response.ok.
  • Para enviar JSON, use JSON.stringify y configure el encabezado Content-Type.
  • Fetch no tiene una opción de tiempo de espera predeterminada, así que use AbortSignal.timeout().

La mayoría de las aplicaciones web modernas se comunican con un servidor todo el tiempo. La JavaScript Fetch API es la forma estándar de hacerlo y está integrada en los navegadores y en Node.js 18 y posteriores, por lo que no hay nada que instalar.

El uso básico requiere dos líneas, sin embargo, muchos tutoriales se detienen ahí y omiten la parte que causa errores reales: el manejo de fallas. Probamos los ejemplos de esta guía en un pequeño servidor local en Node.js 24 y el resultado que se muestra proviene de esa ejecución. example.com en el código representa su propia API. Si las promesas son nuevas para usted, comience con la Explicación de las promesas de JavaScript.

¿Qué es la API de recuperación?

Fetch es una interfaz basada en promesas para realizar solicitudes HTTP. Reemplazó al antiguo XMLHttpRequest basado en devolución de llamadas, y muchos proyectos ahora lo usan en lugar de agregar una biblioteca para llamadas simples.

Característica buscar Axios (biblioteca)
Instalación Construido en Agregado como dependencia
cuerpo JSON Stringifícalo tú mismo Automático
Analizar la respuesta JSON Llamar response.json() Automático
¿Rechazan errores HTTP? No Sí, por defecto
Tiempo de espera A través de AbortSignal Una opción timeout

Una solicitud GET

Fetch realiza una solicitud GET de forma predeterminada. Hay dos pasos y cada uno necesita await: primero llegan los encabezados de respuesta y luego lees el cuerpo.

const response = await fetch("https://example.com/users/1");
const user = await response.json();

console.log(user);

// { id: 1, name: 'Asha' }

Los dos pasos existen porque el cuerpo puede ser grande y llegar más tarde que las cabeceras. En un script de navegador, el nivel superior await necesita un módulo, por lo que normalmente lo colocarás dentro de una función async. Consulte nuestra guía de JavaScript async/await.

El objeto de respuesta

Antes de leer el cuerpo, puedes inspeccionar la respuesta:

console.log(response.status, response.ok, response.headers.get("content-type"));

// 200 true application/json
Propiedad o método te da
response.ok true para los estados 200 a 299
response.status El código de estado, como 404
response.headers.get(name) Un encabezado de respuesta
response.json() El cuerpo analizado como JSON
response.text() El cuerpo como una cuerda
response.blob() Datos binarios, como una imagen.

Un cuerpo sólo se puede leer una vez. Llamar a json() por segunda vez falló en nuestra prueba:

await res.json();
await res.json();

// TypeError: Body is unusable: Body has already been read

Si necesita leerlo dos veces, llame primero al response.clone().

La gran sorpresa: un 404 no tira

Esto es lo más importante de este artículo. Solicitamos un usuario que no existe:

const res = await fetch("https://example.com/users/999");
console.log(res.status, res.ok);

// 404 false

No se lanzó ninguna excepción. En lo que respecta a la recuperación, la solicitud funcionó: se contactó al servidor y respondió. La promesa se rechaza sólo cuando no llega ninguna respuesta utilizable, como ocurre con una falla de la red. Entonces un código como este tiene un error oculto:

try {
  const res = await fetch(url);
  const data = await res.json();   // may be an error payload
  showUser(data);                  // runs anyway for 404 and 500
} catch (error) {
  showError();                     // does not run for 404 or 500
}

Consulte nuestra hoja de referencia de códigos de estado HTTP para ver qué significa cada código.

Un ayudante reutilizable

No repitas ese control en todas partes. Envuélvalo una vez:

async function getJson(url, options) {
  const response = await fetch(url, options);
  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }
  return response.json();
}

try {
  await getJson("https://example.com/users/999");
} catch (error) {
  console.log("caught:", error.message);
}

// caught: Request failed with status 404

Ahora los errores HTTP y los errores de red terminan en lo mismo catch. Vale la pena tener esta pequeña función en cada proyecto. Una versión real también podría leer un mensaje de error del cuerpo de la respuesta y manejar una respuesta 204 No Content, que no tiene JSON para analizar.

PUBLICAR datos JSON

Pase un objeto de opciones como segundo argumento. Para JSON, debes hacer dos cosas tú mismo: convertir los datos en una cadena y configurar el encabezado.

const created = await getJson("https://example.com/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Ben" }),
});

console.log(created);

// { id: 2, name: 'Ben', type: 'application/json' }

Nuestro servidor de prueba respondió el tipo de contenido que recibió, confirmando que llegó el encabezado. Olvidar ese encabezado es una causa común de errores confusos del servidor, porque muchos marcos solo analizan JSON cuando se declara. Para cargar un formulario o archivos, pase un objeto FormData como cuerpo y no establezca Content-Type, ya que el navegador necesita agregar un valor de límite.

Otros métodos y opciones

Opción Ejemplo Propósito
método "PUT", "PATCH", "DELETE" El método HTTP
encabezados { Autorización: "Portador..." } Solicitar encabezados
cuerpo JSON.stringify(data) El cuerpo de la solicitud
señal AbortSignal.timeout(5000) Cancelando
credenciales "incluir" Envío de cookies de origen cruzado
caché "sin tienda" Comportamiento de la caché del navegador

¿Elegir entre REST y otros estilos de API? Nuestra comparación de REST vs GraphQL muestra cómo la recuperación encaja con cada uno.

cadenas de consulta

No cree cadenas de consulta uniendo texto, porque los caracteres especiales las romperán. URLSearchParams maneja la codificación por usted:

const params = new URLSearchParams({ q: "red shoes", page: 2 });
console.log(params.toString());

// q=red+shoes&page=2

await getJson(`https://example.com/search?${params}`);

// { q: 'red shoes', page: '2' }

El servidor recibió red shoes correctamente, con el espacio restaurado.

Tiempos de espera y cancelaciones

Fetch esperará mucho tiempo en un servidor lento a menos que le indique lo contrario. AbortSignal.timeout() establece un límite. Nuestro punto final de prueba tardó dos segundos, frente a un límite de 200 milisegundos:

try {
  await fetch("https://example.com/slow", { signal: AbortSignal.timeout(200) });
} catch (error) {
  console.log(error.name);
}

// TimeoutError

Para cancelar manualmente, por ejemplo, cuando un usuario abandona una página o escribe un nuevo término de búsqueda, utilice un AbortController:

const controller = new AbortController();
const pending = fetch("https://example.com/slow", { signal: controller.signal });

controller.abort();

try {
  await pending;
} catch (error) {
  console.log(error.name);
}

// AbortError

Para ejecutar varias solicitudes a la vez, use Promise.all, que es mucho más rápido que esperarlas una a la vez:

const [user, search] = await Promise.all([
  getJson("https://example.com/users/1"),
  getJson("https://example.com/search?q=a&page=1"),
]);

Todo tipo de fracaso

Así es como se vio cada falla en nuestra ejecución, junto con cómo diferenciarlas:

Situación que pasa como detectarlo
El servidor devuelve 404 o 500 La promesa se cumple response.ok es falso
No se puede acceder al servidor Rechaza con TypeError atrapar
Se alcanzó el tiempo de espera Rechaza con TimeoutError error.name
Cancelado manualmente Rechaza con AbortError error.name
El cuerpo no es JSON válido json() rechaza con SyntaxError atrapar

Esa última fila es común en producción. Un proxy que devuelve un 502 a menudo envía una página de error HTML. Reproducimos esto y res.json() arrojó un SyntaxError. Marcar response.ok antes de analizar significa informar el problema real en lugar de un error de análisis confuso.

Consejo: Pruebe estas rutas de falla a propósito. Las herramientas de desarrollo del navegador pueden simular estar desconectado y las herramientas de prueba pueden simular una respuesta 500. Nuestra guía Pruebas de API con Postman cubre la verificación del lado de la API.

CORS y credenciales

En un navegador, una solicitud de un origen a otro está sujeta a CORS, las reglas de intercambio de recursos entre orígenes. Si ve un error que menciona Access-Control-Allow-Origin, la solución pertenece al servidor, que debe permitir su sitio. En su JavaScript, el error aparece solo como un TypeError genérico, así que mire la consola del navegador para conocer el motivo real. Node.js no aplica CORS, por lo que una solicitud que funcione en un script aún puede fallar en el navegador.

De forma predeterminada, los navegadores no envían cookies en solicitudes de origen cruzado. Configure credentials: "include" si los necesita y asegúrese de que el servidor lo permita. Nunca coloque claves API secretas en el JavaScript del navegador, ya que cualquiera puede leerlas. Mantenlos en tu servidor.

Errores comunes

  • No marcar response.ok. Las respuestas de error se tratan como exitosas.
  • Olvidar el segundo await. response.json() también devuelve una promesa.
  • Olvidar JSON.stringify. Pasar un objeto mientras el cuerpo envía [object Object].
  • Configurando Content-Type con FormData. Esto rompe el límite, así que déjalo fuera.
  • Sin tiempo de espera. Una solicitud colgada puede dejar el control giratorio de una página funcionando indefinidamente.
  • Analizando JSON en busca de una respuesta vacía. Un 204 no tiene cuerpo y json() arrojará.

Conclusión

Fetch es simple una vez que recuerdas su regla principal: una respuesta no es lo mismo que un éxito. Copie el pequeño ayudante en su proyecto, agregue un tiempo de espera y pruebe sus rutas de falla. Como siguiente paso, cree una página pequeña que cargue datos desde una API, muestre un mensaje de error claro y permita al usuario cancelar una búsqueda lenta.

Preguntas frecuentes

¿La recuperación arroja un error en un 404?

No. Fetch solo rechaza cuando no se recibe respuesta, como en el caso de una falla de red. Para errores HTTP, verifique usted mismo Response.ok o Response.status.

¿Cómo envío JSON con recuperación?

Establezca el método en POST, agregue un encabezado Content-Type de application/json y pase los datos a través de JSON.stringify como cuerpo.

¿Por qué necesito dos esperas con recuperación?

El primero se resuelve una vez que llegan los encabezados de respuesta. El segundo espera a que el cuerpo se descargue y se analice, lo que puede ocurrir más adelante.

¿Cómo establezco un tiempo de espera para la recuperación?

Señal de paso: AbortSignal.timeout(5000) en las opciones. Luego, la solicitud se rechaza con un TimeoutError si tarda más de esa cantidad de milisegundos.

¿La recuperación está disponible en Node.js?

Sí. Fetch está disponible globalmente en Node.js 18 y versiones posteriores. Las versiones anteriores necesitan un paquete, aunque las reglas CORS solo se aplican en los navegadores.

sigue aprendiendo

Trabajar con Stack Quora

¿Necesitas ayuda con pruebas, WordPress o SEO?

Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.

Sigue leyendo

Más guías sobre testing, IA y desarrollo moderno

¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.

Inteligencia artificial

Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas

Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…

Leer artículo →
DevOps

Explicación de las variables de entorno: archivos .env, secretos y configuración bien hechos

Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…

Leer artículo →
Desarrollo de software

Explicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429

La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …

Leer artículo →
Automatización de pruebas

Burlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan

Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…

Leer artículo →
Pruebas de software

Explicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%

Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…

Leer artículo →
Bases de datos y SQL

DELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno

DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…

Leer artículo →
Bases de datos y SQL

Vistas SQL explicadas: cree, use y evite los errores, con ejemplos

Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…

Leer artículo →
Desarrollo de software

Interfaz TypeScript versus tipo: diferencias reales, probadas con el compilador

Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…

Leer artículo →
Desarrollo de software

Python *args y **kwargs explicados: funciones flexibles con ejemplos claros

Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…

Leer artículo →
Desarrollo de software

Funciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas

Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…

Leer artículo →
Inteligencia artificial

¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar

¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…

Leer artículo →
DevOps

Monitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos

Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…

Leer artículo →
DevOps

Docker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta

Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…

Leer artículo →
Automatización de pruebas

TDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …

Leer artículo →
Pruebas de software

Pruebas de Aceptación de Usuario (UAT): Proceso, Lista de Verificación y Ejemplos Reales

Explicación de las pruebas de aceptación del usuario: quién las ejecuta, en qué se diferencia del control de calidad, un proceso de siete pasos, una…

Leer artículo →
Bases de datos y SQL

Valores NULL de SQL explicados: IS NULL, COALESCE, NULLIF y las trampas que se deben evitar

Los valores NULL de SQL se explican con las consultas que ejecutamos: lógica de tres valores, IS NULL, COALESCE, NULLIF, cómo los agregados, las uni…

Leer artículo →
Bases de datos y SQL

Declaración SQL CASE WHEN: sintaxis, ejemplos reales y errores comunes

CASO SQL CUANDO se explicó con las consultas que ejecutamos: formularios simples y buscados, orden de condiciones, pivotes con SUMA, trucos COUNT, c…

Leer artículo →
Desarrollo de software

¿Qué es JWT? Tokens web JSON explicados con un ejemplo práctico

¿Qué es JWT? JSON Web Tokens explicó: las tres partes, un token creado y manipulado en el código que ejecutamos, JWT vs sesiones, almacenamiento, to…

Leer artículo →
Desarrollo de software

Explicación del bucle de eventos de JavaScript: pila de llamadas, microtareas y temporizadores con ejemplos

El bucle de eventos de JavaScript explicado con el código que ejecutamos: pila de llamadas, colas de tareas y microtareas, por qué setTimeout 0 no e…

Leer artículo →
Desarrollo de software

Explicación de los generadores y el rendimiento de Python: ahorre memoria con ejemplos reales

Los generadores de Python y el rendimiento se explican con el código que ejecutamos: cómo se pausan y reanudan, midieron el ahorro de memoria, canal…

Leer artículo →
Inteligencia artificial

¿Qué son las incrustaciones? Los vectores y la similitud del coseno se explican de forma sencilla

¿Qué son las incrustaciones? Una guía en lenguaje sencillo sobre vectores, similitud de cosenos y búsqueda semántica, con un pequeño ejemplo que eje…

Leer artículo →
DevOps

Implementación azul-verde versus implementación canaria: diferencias, compensaciones y cómo elegir

Explicación de la implementación azul-verde versus canaria: cómo funciona cada uno, costo, riesgo y reversión, agrupación estable de usuarios que pr…

Leer artículo →
Automatización de pruebas

Pruebas inestables: qué las causa y cómo solucionarlas para siempre

Pruebas inestables explicadas con demostraciones que realizamos: las causas principales, cómo confirmar y diagnosticar una, correcciones adecuadas p…

Leer artículo →
Pruebas de software

Pruebas de carga frente a pruebas de estrés: diferencias, métricas y ejemplos de k6

Explicación de las pruebas de carga frente a las pruebas de estrés: qué prueba cada una, pruebas de picos y de absorción, las métricas que importan,…

Leer artículo →
Pruebas de software

Caso de prueba frente a escenario de prueba: diferencias clave, ejemplos y cuándo utilizar cada uno

Caso de prueba versus escenario de prueba explicado: definiciones claras, una tabla en paralelo, una función de restablecimiento de contraseña tomad…

Leer artículo →
Bases de datos y SQL

Optimización de consultas SQL: lea planes de ejecución y corrija consultas lentas, con tiempos

Optimización de consultas SQL probada en un millón de filas: lea planes de ejecución, agregue los índices correctos, corrija filtros no sargables, u…

Leer artículo →
Bases de datos y SQL

SQL UNION vs UNION ALL: diferencias, ejemplos y rendimiento probado

SQL UNION vs UNION ALL explicado con consultas que ejecutamos: duplicados, las reglas que siguen ambos, un error de datos real, rendimiento medido, …

Leer artículo →
Desarrollo de software

Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

Un tutorial de JavaScript Fetch API probado en un servidor local: GET y POST, por qué 404 no arroja, un asistente reutilizable, cadenas de consulta,…

Leer artículo →
Desarrollo de software

Manejo de archivos Python: lectura, escritura, CSV, JSON y pathlib con ejemplos

El manejo de archivos Python se explica con el código que ejecutamos: modos abiertos, lectura de archivos grandes, CSV, JSON, pathlib, archivos bina…

Leer artículo →
Desarrollo de software

Git merge vs rebase: diferencias, ejemplos y cuándo usar cada uno

Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.

Leer artículo →
Desarrollo de software

List comprehension en Python: sintaxis, ejemplos y cuándo evitarla

List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.

Leer artículo →