Enviar datos con Fetch API en JavaScript
Aprende a enviar datos con Fetch API de forma eficiente. En esta guía técnica exploramos cómo configurar peticiones HTTP POST, gestionar el objeto JSON y manipular las headers para una comunicación segura entre cliente y servidor. Domina el uso de Async/Await para optimizar el envío de formularios y el procesamiento de respuestas en aplicaciones web modernas.

Índice
1. ¿Qué significa enviar datos con Fetch?
Enviar datos con Fetch API en JavaScript significa realizar una petición HTTP desde el navegador hacia un servidor para transferir información, generalmente utilizando métodos como POST, PUT o PATCH. Este proceso es fundamental en el desarrollo web moderno, ya que permite que las aplicaciones interactúen con APIs y bases de datos sin recargar la página.
A diferencia de una petición GET con Fetch API (que solo obtiene información), cuando enviamos datos con estamos transmitiendo información desde el cliente al backend, como formularios, credenciales de usuario o contenido dinámico. Estos datos suelen enviarse en el body de la petición, comúnmente en formato JSON o FormData.
En JavaScript moderno, este proceso se realiza utilizando Fetch API junto con async/await, lo que permite escribir código más limpio, legible y fácil de mantener. Además, se pueden configurar aspectos clave como los headers, el tipo de contenido (Content-Type) y la estructura de los datos enviados.
En términos prácticos, enviar datos con fetch implica:
- Definir el método HTTP adecuado (POST, PUT, PATCH)
- Preparar los datos a enviar (JSON.stringify o FormData)
- Configurar la petición con headers y opciones
- Procesar la respuesta del servidor
Este flujo es esencial para crear aplicaciones web interactivas, dinámicas y conectadas a servicios externos.
1.1. Casos comunes y reales donde se envían datos con Fetch
En el desarrollo web moderno, enviar datos es una acción constante para mantener la interactividad. Aquí te presento los escenarios más frecuentes donde aplicarás esta tecnología:
- Formularios de Registro e Inicio de Sesión
- Es el uso más crítico. Capturamos los datos que el usuario escribe (email, contraseña) y los enviamos al servidor para su validación o almacenamiento en una base de datos. Es esencial para la autenticación de usuarios.
- Envío de Formularios de Contacto
- En lugar de recargar la página tras hacer clic en «Enviar», usamos Fetch para mandar el mensaje y mostrar un aviso de «¡Éxito!» al instante mediante el DOM. Permite una experiencia más fluida sin recargas.
- Pasarelas de Pago y Carritos de Compra
- Cuando un usuario añade un producto o confirma una compra, Fetch comunica al servidor los IDs de los artículos y los detalles de la transacción de forma segura. Es clave en procesos de compra online.
- Actualización de Perfil de Usuario
-
Al cambiar tu foto o biografía en una red social, se realiza una petición (usualmente
PUToPATCH) que actualiza solo esa porción de información en el servidor. Permite modificar datos sin recargar toda la aplicación. - Sistemas de Comentarios y «Likes»
- Cada vez que das «me gusta» a una publicación o escribes una respuesta, estás enviando una pequeña cantidad de datos mediante Fetch para que ese cambio se guarde permanentemente. Hace posible la interacción en tiempo real.
- Carga de Archivos e Imágenes
-
Fetch permite enviar objetos de tipo
BloboFile, facilitando que los usuarios suban documentos a la nube sin interrumpir su navegación. Es fundamental para la subida de archivos moderna.
2. ¿Cómo enviar datos con Fetch()?
Antes de sumergirnos en cómo enviar información a una base de datos, es vital recordar que la Fetch API es, por naturaleza, una herramienta de consulta.
Su función principal es conectar tu aplicación con una URL para intercambiar recursos.
Entonces, primero debemos conocer como es la sintaxis general de una petición con Fetch, con la cuál podemos recibir datos, para luego profundizar en cómo hacer para enviarlos:
fetch(
URL, // 1. Destino (Obligatorio): ¿A dónde vamos?
{ CONFIGURACIÓN } // 2. Opciones (Opcional): ¿Cómo vamos y qué llevamos?
)
.then(respuesta => {
// 3. Procesamiento: ¿Qué hacemos con lo que recibimos?
})
.catch(error => {
// 4. Gestión de errores: ¿Qué hacemos si algo sale mal en la red?
});Lenguaje del código: JavaScript (javascript)
¿Por qué a veces no configuramos nada?
Una de las mayores ventajas de JavaScript es que simplifica las tareas más comunes. Si tú ejecutas un fetch(URL) y omites el segundo parámetro (el objeto de configuración), el navegador asume dos cosas de forma automática:
- El método es GET:
- Asume que tu intención es únicamente recibir o leer datos desde el servidor.
- Sin cuerpo de datos:
- Entiende que no estás enviando información adicional (como un usuario o una contraseña), sino que solo estás haciendo una petición de «solo lectura».
Es por esto que, para listar productos en un e-commerce o traer el clima actual, el código se ve tan limpio. Sin embargo, en el mundo real, las aplicaciones no solo leen información; también crean, actualizan y borran.
EL SIGUIENTE PASO: De recibir a ENVIAR
Ahora que tenemos claro que por defecto Fetch es un sistema de recepción de datos (GET), estamos listos para romper ese comportamiento estándar.
Para transformar una simple petición de lectura en una potente herramienta de envío de datos, necesitamos aprender a «llenar» ese objeto de CONFIGURACIÓN que mencionamos arriba.
En las siguientes secciones, veremos cómo decirle a Fetch que queremos usar otros métodos y cómo preparar el «paquete» de datos que queremos entregar al servidor.
2.1. El objeto de opciones (configuración):
Cuando queremos ir más allá del comportamiento por defecto, el segundo parámetro de fetch() —el objeto de opciones— (configuración en la sintaxis primera) se vuelve el protagonista. Aquí es donde definimos las reglas del juego para la comunicación con el servidor.
Estructura completa de configuración
A continuación, verás las propiedades más importantes que podés incluir. Aunque en el 90% de los casos usarás solo las tres primeras, conocer las demás te permitirá resolver problemas complejos de seguridad y rendimiento.
fetch(URL, {
method: 'POST', // 1. Método HTTP
headers: { // 2. Cabeceras de la petición
'Content-Type': 'application/json',
'Authorization': 'Bearer tu_token_aqui'
},
body: JSON.stringify({}), // 3. El cuerpo de los datos
mode: 'cors', // 4. Modo de la petición (CORS, no-cors, same-origin)
credentials: 'include', // 5. Manejo de cookies y autenticación
cache: 'default', // 6. Estrategia de caché del navegador
signal: controller.signal // 7. Permite cancelar la petición (AbortController)
});Lenguaje del código: JavaScript (javascript)
Explicación técnica de cada propiedad:
method:- Indica la acción a realizar. Por defecto es
GET, pero para enviar datos usamosPOST(crear),PUT(reemplazar) oPATCH(modificar parcialmente).
- Indica la acción a realizar. Por defecto es
headers:- Es un objeto con metadatos. El más común es
Content-Type, que le avisa al servidor en qué formato viajan los datos (generalmente JSON).
- Es un objeto con metadatos. El más común es
body:- Es la información real que enviamos. Puede ser un string JSON, un objeto
FormDatao incluso un archivo binario. Nota: No se puede usar en peticiones GET o HEAD.
- Es la información real que enviamos. Puede ser un string JSON, un objeto
mode:- Define si la petición puede cruzar dominios (CORS). Es vital para consumir APIs que están en servidores diferentes al de tu web.
credentials:- Indica si el navegador debe enviar automáticamente cookies o cabeceras de autenticación TLS con la petición.
cache:- Controla cómo interactúa la petición con la caché del navegador (si debe buscar una copia guardada o pedir datos frescos siempre).
signal:- Es una herramienta avanzada que permite «abortar» o cancelar la petición si el usuario navega a otra página o si tarda demasiado.
3. El atributo method
El atributo method en el objeto de configuración de Fetch determina qué tipo de operación queremos realizar sobre el recurso en la URL de destino.
En otras palabras;
Es la propiedad que define qué tipo de acción HTTP querés realizar sobre el servidor, o sea, qué queremos hacer con los datos:
- Obtenerlos – GET (Por defecto)
- Enviarlos – POST
- Actualizarlos – PUT
- Eliminarlos -DELETE
Por defecto, si no definís esta propiedad, Fetch ejecutará un método GET, y no profundizamos en este método ya que lo vimos en este artículo sobre Fetch API en JS.
3.1. Guía de uso: ¿Cuándo usar cada método?
Para que tu código sea profesional y semánticamente correcto, debés elegir el método según la acción que deseas ejecutar:
POST (Crear)
- Es el método estándar para enviar datos que resultarán en la creación de un nuevo recurso en el servidor.
- ¿Para qué sirve?: Se usa cuando el cliente (tu web) envía información que aún no existe en la base de datos.
- Ejemplo real: Registrar un nuevo usuario, publicar un comentario o realizar una compra.
PUT (Reemplazar/Actualizar)
- Se utiliza para actualizar un recurso existente, enviando la versión completa y actualizada del mismo.
- ¿Para qué sirve?: Sirve para realizar una sustitución total. Si el recurso no existe, en algunos sistemas puede llegar a crearlo.
- Ejemplo real: Editar un perfil de usuario donde se envían nuevamente todos los campos (nombre, apellido, bio) para sobreescribir los anteriores.
PATCH (Modificar parcialmente)
- A diferencia de PUT, PATCH se utiliza para aplicar modificaciones parciales a un recurso.
- ¿Para qué sirve?: Es más eficiente cuando solo queremos cambiar un dato específico sin necesidad de enviar todo el objeto de nuevo.
- Ejemplo real: Cambiar únicamente la contraseña de un usuario o marcar una tarea como «completada» en una lista de pendientes.
3.2. Ejemplo práctico
fetch('https://api.ejemplo.com/usuarios', {
method: 'POST'
});Lenguaje del código: JavaScript (javascript)
Acá le estás diciendo al servidor: “quiero enviar datos nuevos”
4. El atributo headers.
Es un objeto que permite definir metadatos de la petición HTTP, es decir, información adicional que describe cómo se envían los datos y cómo deben ser interpretados por el servidor.
En el envío de datos con Fetch, las cabeceras son obligatorias para que el servidor sepa cómo interpretar el flujo de bytes que le estás enviando.
4.1. Cómo configurar las Headers
Existen dos formas de definir las cabeceras en Fetch. La más común es mediante un objeto literal, pero la forma más profesional y escalable es usando el constructor Headers().
Opción 1: Objeto literal (La más usada)
Es ideal para peticiones rápidas y sencillas.
const opciones = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token_de_seguridad'
},
body: JSON.stringify({ usuario: 'DevMaster' })
};Lenguaje del código: JavaScript (javascript)
Opción 2: Constructor new Headers() (Recomendado para apps grandes)
Permite manipular las cabeceras de forma dinámica (agregar, borrar o consultar).
const misCabeceras = new Headers();
misCabeceras.append('Content-Type', 'application/json');
misCabeceras.append('Accept', 'application/json');
fetch(URL, {
method: 'POST',
headers: misCabeceras,
body: JSON.stringify({ id: 101 })
});Lenguaje del código: JavaScript (javascript)
4.2. Los encabezados más utilizados y su función
A continuación, los encabezados que todo desarrollador de JavaScript debe conocer para trabajar con APIs profesionales:
4.2.1. Content-Type (El más importante)
- Indica al servidor el formato original de los datos que estás enviando en el
body. - Uso común:
application/json(para objetos JSON),text/plain(texto plano) omultipart/form-data(para subir archivos).
4.2.2. Authorization (Seguridad)
- Se utiliza para enviar credenciales que demuestren que el usuario tiene permiso para realizar la acción.
- Uso común:
Bearer <token>(usado con JSON Web Tokens o JWT). Es esencial para proteger rutas privadas de una API.
4.2.3. Accept (Negociación de contenido)
- Le dice al servidor qué tipo de formato de respuesta espera recibir el cliente.
- Uso común:
application/json. Si el servidor puede responder en varios formatos (XML o JSON), este encabezado le indica cuál prefieres.
4.2.4. Cache-Control (Rendimiento)
- Define las reglas de almacenamiento en caché para la petición.
- Uso común:
no-cache(obliga a buscar datos frescos),max-age=3600(permite usar datos guardados por una hora).
4.2.5. X-API-KEY (Personalizados)
- Muchos servicios de terceros (como Google Maps o APIs de clima) requieren una clave de acceso única que no es un token de usuario.
- Uso común: Identificar la aplicación que está haciendo la consulta para límites de cuota y facturación.
4.3. Buenas prácticas y Errores comunes
- Sensibilidad a mayúsculas:
- Aunque las cabeceras HTTP suelen ser case-insensitive, por convención y legibilidad siempre se escriben como
'Content-Type'.
- Aunque las cabeceras HTTP suelen ser case-insensitive, por convención y legibilidad siempre se escriben como
- No olvides el formato:
- Si declarás
application/json, asegurate de que tubodysea realmente un string generado conJSON.stringify(). Si envías un objeto de JS puro, la petición fallará.
- Si declarás
- Seguridad:
- Nunca pongas contraseñas directamente en las headers. Usá cabeceras de autorización (
Authorization) con tokens seguros (JWT).
- Nunca pongas contraseñas directamente en las headers. Usá cabeceras de autorización (
5. El atributo body
Si comparamos una petición Fetch con un servicio de mensajería, el body (cuerpo) es el contenido real dentro de la caja. Es la propiedad donde colocamos la información que queremos que el servidor reciba, procese y guarde en su base de datos.
5.1. ¿Para qué sirve el body?
Su función es transportar la «carga útil» (payload) de la petición. Sin el body, el servidor sabría qué quieres hacer (gracias al method) y quién eres (gracias a los headers), pero no tendría los datos para ejecutar la acción (por ejemplo, no sabría qué nombre de usuario quieres registrar).
NOTA!! El body solo se utiliza en métodos que permiten enviar datos, como POST, PUT y PATCH. Intentar usarlo en una petición GET arrojará un error, ya que GET solo debe solicitar información a través de la URL.
5.2. ¿Cómo usarlo correctamente? (El proceso de serialización)
Un error común es intentar pasar un objeto de JavaScript directamente al body. Los servidores no entienden objetos de JS «vivos»; solo entienden texto (strings).
Por eso, debemos serializar los datos. El proceso estándar es:
- Tener un objeto JS con los datos.
- Convertirlo a una cadena de texto JSON usando
JSON.stringify(). - Pasarlo a la propiedad
body.
5.3. Ejemplo práctico
Imagina que quieres enviar los datos de un nuevo artículo para tu blog:
// 1. Definimos nuestros datos como un objeto JS normal
const nuevoPost = {
titulo: "Dominando Fetch API",
autor: "Tu Nombre",
contenido: "Hoy aprenderemos a usar el body..."
};
// 2. Configuramos la petición
fetch('https://api.tu-sitio.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
// 3. Convertimos el objeto a texto JSON
body: JSON.stringify(nuevoPost)
})
.then(res => res.json())
.then(datos => console.log("Post creado:", datos));Lenguaje del código: JavaScript (javascript)
Explicación del ejemplo:
JSON.stringify(nuevoPost):- Esta función transforma
{titulo: "..."}en'{"titulo": "..."}'. Ahora los datos son una cadena de texto plana que puede viajar por los cables de internet sin corromperse.
- Esta función transforma
- Sincronía con headers:
- Al usar este método, es obligatorio que en tus
headershayas declarado'Content-Type': 'application/json', para que el servidor sepa que debe hacer el proceso inverso (deserializar) al recibir el paquete.
- Al usar este método, es obligatorio que en tus
5.4. Tipos de datos que acepta el body
Aunque JSON es el rey, el body es flexible y puede transportar otros formatos según el proyecto:
- JSON: El más usado para APIs (como vimos arriba).
- FormData: Ideal para enviar formularios con archivos o imágenes directamente desde el DOM.
- Blob / Buffer: Para datos binarios puros (archivos, audio).
- URLSearchParams: Para enviar datos como si fueran una cadena de consulta de formulario antiguo.
6. El atributo mode
Sirve para establecer las reglas de seguridad y los límites de alcance de tu petición.
Le indica al navegador si la comunicación se mantendrá dentro del mismo servidor o si tiene permiso para realizar una petición «transfronteriza» (a otro dominio).
6.1. ¿Para qué sirve el mode?
Su función principal es la seguridad. El navegador utiliza esta configuración para decidir si debe aplicar el protocolo CORS (Cross-Origin Resource Sharing). Esto evita que scripts maliciosos de un sitio web roben datos de otro sitio sin permiso.
6.2. Los 3 valores principales de mode
cors(Valor por defecto):- Permite peticiones a otros dominios siempre que el servidor de destino lo autorice mediante cabeceras especiales. Es lo que usás para conectarte a APIs externas.
no-cors:- Es un modo muy limitado. Solo permite peticiones básicas y no permite leer la respuesta del servidor desde JavaScript. Se usa a veces para «notificaciones» donde no te importa el resultado.
same-origin:- Garantiza que la petición solo se realice al mismo dominio donde está alojada tu web. Si intentás llamar a una API externa, la petición fallará automáticamente.
6.3. Ejemplo práctico
Imagina que tu sitio web está en misitio.com y querés enviar datos a una API en api-externa.com.
// Ejemplo de configuración con modo CORS explícito
fetch('https://api-externa.com/usuarios', {
method: 'POST',
mode: 'cors', // Indicamos que vamos a otro dominio
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ nombre: "Dev" })
})
.then(response => {
console.log("¿Petición exitosa?", response.ok);
})
.catch(error => {
console.error("Error de CORS o Red:", error);
});Lenguaje del código: JavaScript (javascript)
Explicación del ejemplo:
- Al poner
mode: 'cors', el navegador envía primero una «pre-petición» (llamada OPTIONS) al servidor externo para preguntar: «¿Tengo permiso para enviarte estos datos?». - Si el servidor responde que sí, la petición real se ejecuta. Si el servidor no está configurado para aceptar peticiones de tu dominio, el navegador bloqueará la respuesta por seguridad.
7. El atributo credentials.
El atributo credentials le indica al navegador si debe incluir información de autenticación automática (como cookies, certificados TLS o cabeceras de autenticación HTTP) en la petición fetch.
7.1. ¿Para qué sirve credentials?
Por motivos de seguridad, los navegadores suelen ser restrictivos con el envío de cookies a otros dominios para evitar ataques de tipo CSRF (Cross-Site Request Forgery).
Esta propiedad permite al desarrollador decidir explícitamente si quiere compartir la sesión del usuario con el servidor al que está enviando los datos.
7.2.Los 3 valores de credentials
same-origin(Valor por defecto en muchos navegadores):- Solo envía cookies y datos de autenticación si la petición se realiza al mismo dominio donde está alojada tu web.
include:- Envía siempre las credenciales, incluso si la petición es a un dominio diferente (CORS). Es fundamental si tu API está en un subdominio o servidor externo y necesitas mantener la sesión iniciada.
omit:- Nunca envía credenciales ni permite que el servidor guarde cookies que vengan en la respuesta. Es la opción más privada.
7.3. Ejemplo práctico
Imagina que tienes una aplicación donde el usuario ya inició sesión y quieres enviar un comentario. El servidor necesita la cookie de sesión para saber quién escribe.
fetch('https://api.tu-sitio.com/comentarios', {
method: 'POST',
// Configuramos credentials para incluir la sesión del usuario
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ texto: "¡Excelente tutorial!" })
})
.then(response => {
if (response.ok) console.log("Comentario enviado con tu sesión activa");
});Lenguaje del código: JavaScript (javascript)
Explicación del ejemplo:
- Al usar
credentials: 'include', el navegador busca cualquier cookie guardada paraapi-tu-sitio.comy la adjunta automáticamente a la petición. - Nota importante para el servidor: Si usas
'include'en una petición a otro dominio, el servidor debe responder con la cabeceraAccess-Control-Allow-Credentials: true, de lo contrario, el navegador bloqueará la respuesta por seguridad.
8. El atributo cache.
Define cómo debe interactuar la petición con el sistema de almacenamiento temporal (caché) del navegador. Sirve para decidir si queremos usar una copia guardada de una respuesta anterior o si obligamos al navegador a realizar un viaje completo hasta el servidor.
8.1. Los valores más importantes de cache
default(Valor por defecto):- El navegador decide según las reglas estándar de HTTP. Si el recurso no ha expirado, usa la caché; si es viejo, consulta al servidor.
no-cache:- El navegador busca en la caché pero siempre consulta al servidor para ver si hay una versión más nueva antes de usarla.
reload:- Ignora completamente la caché y obliga al navegador a pedir los datos directamente al servidor, actualizando la caché con la nueva respuesta.
force-cache:- El navegador usa la copia de la caché sin importar qué tan vieja sea. Si no hay nada guardado, entonces va al servidor.
only-if-cached:- El navegador solo devuelve datos si ya están en la caché. Si no están, lanza un error de red.
8.2. Ejemplo práctico
Imagina que estás enviando una petición para obtener una configuración que rara vez cambia. Queremos que, una vez obtenida, se use siempre la versión guardada para ganar velocidad.
fetch('https://api.tu-sitio.com/configuracion-app', {
method: 'GET', // Usamos GET para este ejemplo de optimización
cache: 'force-cache', // Obligamos al navegador a usar la copia guardada
})
.then(response => response.json())
.then(config => {
console.log("Configuración cargada instantáneamente desde la caché:", config);
});Lenguaje del código: JavaScript (javascript)
Explicación:
- Uso en envíos (POST): Aunque el envío de datos suele ser dinámico, a veces queremos que la respuesta de un envío exitoso se refresque inmediatamente en la memoria del navegador usando
reload. - Al usar
cache: 'force-cache', la segunda vez que el usuario entre a tu web, Fetch no hará ninguna llamada a internet; sacará los datos directamente del disco duro del usuario.
9. El atributo signal
El atributo signal es una propiedad que permite comunicar a una petición Fetch que debe detenerse o «abortarse» antes de que termine de forma natural. Para que funcione, necesita trabajar en conjunto con una interfaz de JavaScript llamada AbortController.
9.1. ¿Para qué sirve signal?
Su función principal es el control de flujo y limpieza. Existen dos casos críticos donde es obligatorio usarlo:
- Limpieza del DOM:
- Si un usuario hace clic en un botón para cargar datos pero decide navegar a otra sección antes de que la petición termine, debemos cancelar la petición para no gastar recursos innecesarios.
- Timeouts (Tiempos de espera):
- Si el servidor tarda demasiado (por ejemplo, más de 5 segundos), podemos usar
signalpara cancelar la petición automáticamente y mostrar un mensaje de «Tiempo de espera agotado».
- Si el servidor tarda demasiado (por ejemplo, más de 5 segundos), podemos usar
9.2. ¿Cómo usarlo en 3 pasos?
- Crear el controlador: Instancias
new AbortController(). - Vincular la señal: Pasas
controller.signalal objeto de configuración de Fetch. - Ejecutar la cancelación: Llamas a
controller.abort()cuando decidas que la petición ya no es necesaria.
9.3. Ejemplo práctico:
Este es el uso más profesional en el mundo real. Si el servidor no responde en 3 segundos, cancelamos todo:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3 segundos de límite
fetch('https://api.tu-sitio.com/datos-pesados', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ consulta: "procesar_todo" }),
// Pasamos la señal al fetch
signal: controller.signal
})
.then(response => response.json())
.then(data => {
clearTimeout(timeoutId); // Si llega a tiempo, cancelamos el temporizador
console.log("Datos recibidos:", data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.warn("¡Petición cancelada por tardar demasiado!");
} else {
console.error("Error de red:", error);
}
});Lenguaje del código: JavaScript (javascript)
Explicación:
AbortController: Crea un «interruptor» para nuestra petición.signal: Es el cable que conecta ese interruptor con elfetch.controller.abort(): Al ejecutarse, Fetch lanza inmediatamente una excepción de tipoAbortError, la cual capturamos en el.catch()para informar al usuario con elegancia.
10. Manejo de respuestas del servidor
Aquí nos referimos al proceso de recibir, interpretar y verificar la respuesta que devuelve el servidor después de una petición fetch.
Cuando enviamos una petición, el servidor siempre responde con información. Esa respuesta puede indicar:
- Que todo salió bien
- Que hubo un error
- Que los datos enviados no eran válidos
- Que el recurso no existe
10.1. Flujo básico de una respuesta
- El navegador envía la petición con
fetch - El servidor responde
fetchdevuelve un objetoResponse- JavaScript debe leer y validar ese objeto
¿QUÉ ES EL objeto response?
Como dijimos, cuando haces un fetch, lo que recibes no son los datos directamente, sino un objeto llamado Response. Este objeto es como una caja cerrada que contiene el resultado del trámite, pero antes de usar lo que hay dentro, debemos revisar las etiquetas de seguridad.
¿QUÉ PASA UNA VEZ RECIBIDO EL objeto response?
Una vez que hemos validado la respuesta y extraído los datos con .json(), el siguiente paso es la manipulación del DOM. El navegador no muestra mensajes automáticamente; somos nosotros los que debemos «dibujar» el resultado.
¿Qué acciones prácticas realizamos en el DOM?
Dependiendo de lo que responda el servidor, estas son las acciones más comunes que deberías incluir en tu tutorial:
- Feedback Visual de Éxito o Error
- Es la acción más básica. Usamos elementos HTML (como un
<div>o<span>) para informar al usuario.- En la práctica: Cambiamos el texto con
.textContenty el color con.styleo.classList. - Ejemplo: «¡Registro exitoso!» en verde o «El correo ya existe» en rojo.
- En la práctica: Cambiamos el texto con
- Es la acción más básica. Usamos elementos HTML (como un
- Limpieza del Formulario
- Si el envío fue exitoso, lo profesional es no dejar los datos escritos para evitar que el usuario los envíe dos veces por error.
- En la práctica: Usamos el método
formulario.reset()para vaciar todos los campos de un solo golpe.
- En la práctica: Usamos el método
- Si el envío fue exitoso, lo profesional es no dejar los datos escritos para evitar que el usuario los envíe dos veces por error.
- Estados de Carga (Loading)
- Antes de recibir la respuesta (mientras el
awaitestá trabajando), debemos avisar que algo está pasando.- En la práctica: Deshabilitamos el botón de envío (
button.disabled = true) y cambiamos su texto a «Enviando…». Esto evita peticiones duplicadas.
- En la práctica: Deshabilitamos el botón de envío (
- Antes de recibir la respuesta (mientras el
- Redirección o Navegación
- A veces, tras enviar datos (como en un Login), no queremos mostrar un mensaje, sino llevar al usuario a otra parte.
- En la práctica: Usamos
window.location.href = '/dashboard'para mover al usuario a su panel de control una vez que el servidor confirma que sus credenciales son válidas.
- En la práctica: Usamos
- A veces, tras enviar datos (como en un Login), no queremos mostrar un mensaje, sino llevar al usuario a otra parte.
10.2 Ejemplo práctico
Enviando un mensaje con la estructura .then()
Imagina que enviamos un simple mensaje de texto a una API. Observa cómo el objeto Response aparece en el primer .then():
fetch('https://api.ejemplo.com/enviar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ mensaje: "Hola Mundo" })
})
// Aquí recibimos el objeto Response (lo llamamos 'res')
.then(res => {
console.log("Objeto Response recibido:", res);
if (res.ok) {
return res.json(); // Abrimos la "caja" para sacar los datos
}
throw new Error("Algo salió mal");
})
// Aquí recibimos los DATOS ya procesados
.then(datos => {
console.log("Datos finales:", datos);
})
.catch(error => console.error(error));Lenguaje del código: JavaScript (javascript)
¿QUÉ HACE EXACTAMENTE EL objeto Response?
El objeto Response no son los datos, sino el paquete que los contiene. Su función es darte información sobre el éxito del viaje antes de que gastes tiempo procesando el contenido.
Aquí tenés sus 3 funciones principales explicadas de forma concisa:
- Actúa como un Escudo de Validación (
okystatus)- Antes de mostrar nada en tu web, el objeto
Responsete dice si la petición fue exitosa. - Para qué sirve: Con la propiedad
res.ok(true/false) ores.status(ej. 200, 404), sabés si el servidor aceptó tus datos sin tener que leer todo el mensaje. Es como mirar el sello de una carta antes de abrirla.
- Antes de mostrar nada en tu web, el objeto
- Contiene los Metadatos de la Respuesta (
headers)- El objeto guarda información sobre la respuesta que no es el «mensaje» en sí.
- Para qué sirve: Te permite saber, por ejemplo, en qué formato te está respondiendo el servidor (¿Es un JSON?, ¿Es una imagen?, ¿Es un PDF?) o si te está enviando una nueva cookie de sesión.
- Gestiona el Flujo de Datos (
json(),text(),blob())- El contenido real (el cuerpo) llega como un «flujo» (stream). El objeto
Responsetiene los métodos necesarios para transformar ese flujo en algo que JavaScript entienda. - Para qué sirve: El método
res.json()toma ese flujo y lo convierte en un objeto usable. Dato clave: Al hacer esto, el objeto «vacía» su contenido; por eso solo podés leer el cuerpo de una respuesta una sola vez.
- El contenido real (el cuerpo) llega como un «flujo» (stream). El objeto
11. Ejemplo real de envío de datos
Un caso muy común en proyectos web es un formulario de registro de usuario.
El usuario completa:
- nombre
- contraseña
Cuando hace clic en «Registrarse», JavaScript toma esos datos y los envía a una API para crear el nuevo usuario.
VAMOS CON EL CÓDIGO DEL EJEMPLO:
HTML del formulario
<form id="formRegistro">
<input type="text" id="nombre" placeholder="Nombre" required>
<input type="email" id="email" placeholder="Email" required>
<input type="password" id="password" placeholder="Contraseña" required>
<button type="submit">Registrarse</button>
</form>
<p id="mensaje"></p>
Lenguaje del código: HTML, XML (xml)
Código JavaScript con async/await
// Seleccionamos los elementos del DOM necesarios: el formulario para escuchar el evento y un div/p para mostrar mensajes al usuario.
const formulario = document.querySelector('#formRegistro');
const mensaje = document.querySelector('#mensaje');
// Escuchamos el evento 'submit'. Usamos 'async' porque dentro realizaremos una operación asíncrona (fetch).
formulario.addEventListener('submit', async (event) => {
// Evitamos que la página se recargue, que es el comportamiento por defecto de los formularios.
event.preventDefault();
// Capturamos los valores actuales de los campos de entrada.
const nombre = document.querySelector('#nombre').value;
const email = document.querySelector('#email').value;
const password = document.querySelector('#password').value;
// Creamos un objeto que empaqueta la información del usuario de forma organizada.
const datosUsuario = {
nombre,
email,
password
};
try {
/* CONFIGURACIÓN DEL FETCH:
Aquí iniciamos la petición HTTP. Fetch por defecto es GET, por eso pasamos un segundo
argumento de configuración (un objeto {}) para personalizarlo:
*/
const response = await fetch('https://api.ejemplo.com/usuarios', {
// 1. Definimos el método POST porque estamos enviando (creando) datos en el servidor.
method: 'POST',
/* 2. Definimos los HEADERS (Cabeceras):
'Content-Type': Le dice al servidor que los datos que enviamos están en formato JSON.
'Accept': Le dice al servidor que esperamos recibir una respuesta también en JSON.
*/
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
/* 3. Definimos el BODY (Cuerpo):
Los objetos de JavaScript no se pueden enviar directamente por HTTP.
Usamos JSON.stringify() para convertir nuestro objeto 'datosUsuario' en una cadena de texto JSON.
*/
body: JSON.stringify(datosUsuario)
});
// Validamos si la respuesta fue exitosa (status en el rango 200-299).
// Fetch no lanza error automáticamente si el servidor responde con un 404 o 500, hay que checkearlo manualmente.
if (!response.ok) {
throw new Error(`Error HTTP: ${response.status}`);
}
/* PROCESAMIENTO DE LA RESPUESTA:
await response.json() toma el cuerpo de la respuesta del servidor (que viene como stream)
y lo parsea de nuevo a un objeto de JavaScript para que podamos usarlo.
*/
const resultado = await response.json();
// Si todo salió bien, actualizamos la interfaz con la información recibida (ej. un ID generado).
mensaje.textContent = `Usuario creado correctamente. ID: ${resultado.id}`;
console.log(resultado);
} catch (error) {
// Si ocurre un error de red o lanzamos el error manual en el 'if', el flujo cae aquí.
mensaje.textContent = 'No fue posible registrar el usuario';
console.error(error);
}
});Lenguaje del código: JavaScript (javascript)
Explicación de la configuración de fetch
fetch('https://api.ejemplo.com/usuarios', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(datosUsuario)
})
Lenguaje del código: JavaScript (javascript)
1. method: 'POST'
method: 'POST'Lenguaje del código: JavaScript (javascript)
Indica que la petición va a enviar datos nuevos al servidor.
En este ejemplo, el servidor entiende que debe crear un nuevo usuario.
2. headers
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}Lenguaje del código: JavaScript (javascript)
Content-Type
'Content-Type': 'application/json'Lenguaje del código: JavaScript (javascript)
Le informa al servidor que los datos enviados están en formato JSON.
Sin este header, muchos servidores no podrían interpretar correctamente el contenido del body.
Accept
'Accept': 'application/json'Lenguaje del código: JavaScript (javascript)
Indica que JavaScript espera recibir una respuesta JSON.
3. body
body: JSON.stringify(datosUsuario)Lenguaje del código: JavaScript (javascript)
body contiene los datos que se enviarán al servidor.
La variable datosUsuario contiene:
{
nombre: 'Juan',
email: '[email protected]',
password: '123456'
}Lenguaje del código: CSS (css)
Pero fetch no puede enviar directamente un objeto JavaScript. Por eso se utiliza:
JSON.stringify(datosUsuario)Lenguaje del código: JavaScript (javascript)
Eso transforma el objeto en texto JSON:
{
"nombre": "Juan",
"email": "[email protected]",
"password": "123456"
}Lenguaje del código: JSON / JSON con comentarios (json)
Resultado esperado del código
Si la petición funciona correctamente:
- se crea el usuario en el servidor
- el servidor devuelve información del nuevo usuario
- se actualiza el DOM mostrando un mensaje
Resultado visible:
Usuario creado correctamente. ID: 15
Ejemplo de respuesta que devuelve la API
Supongamos que el servidor responde con este JSON:
{
"id": 15,
"nombre": "Juan",
"email": "[email protected]",
"creado": true
}Lenguaje del código: JSON / JSON con comentarios (json)
Ese JSON llega dentro del objeto response.
Cómo se maneja la respuesta (response)
const response = await fetch(...);Lenguaje del código: JavaScript (javascript)
La variable response no contiene directamente el JSON. Contiene un objeto especial con información sobre la respuesta.
Por ejemplo:
console.log(response);Lenguaje del código: JavaScript (javascript)
Podría mostrar algo parecido a:
Response {
ok: true,
status: 201,
statusText: 'Created'
}Lenguaje del código: CSS (css)
Verificar si la respuesta fue correcta
if (!response.ok) {
throw new Error(`Error HTTP: ${response.status}`);
}Lenguaje del código: JavaScript (javascript)
response.okvaletruesi el código HTTP está entre 200 y 299response.statuscontiene el código exacto
En este caso:
response.status // 201Lenguaje del código: JavaScript (javascript)
201 significa: “recurso creado correctamente”.
Convertir la respuesta a un objeto JavaScript
const resultado = await response.json();Lenguaje del código: JavaScript (javascript)
response.json() toma el JSON devuelto por el servidor y lo transforma en un objeto JavaScript:
{
id: 15,
nombre: 'Juan',
email: '[email protected]',
creado: true
}Lenguaje del código: CSS (css)
⭐Ejemplo completo del flujo
- El usuario completa el formulario
- JavaScript obtiene los valores del DOM
- Se crea el objeto
datosUsuario fetchenvía los datos conPOST- El servidor crea el usuario
- El servidor responde con un JSON
response.json()transforma esa respuesta- JavaScript usa el resultado para actualizar el DOM
- Si ocurre un error,
catchlo captura y muestra un mensaje
⭐Ejemplo de error y respuesta del servidor
Si el email ya existe, la API podría devolver:
{
"error": "El email ya está registrado"
}Lenguaje del código: JSON / JSON con comentarios (json)
Con código HTTP:
409 Conflict
Entonces:
if (!response.ok) {
throw new Error(`Error HTTP: ${response.status}`);
}Lenguaje del código: JavaScript (javascript)
Generaría:
Error HTTP: 409Lenguaje del código: JavaScript (javascript)
Y el catch mostraría el mensaje de error en pantalla.
