javascript

Fetch API en JavaScript: peticiones HTTP con promesas

JavaScript es un lenguaje que evoluciona en todos los sentidos.

Hace tiempo se utilizaba XMLHttpRequest para hacer peticiones AJAX en JavaScript del lado del cliente. Tiempo después aparecieron librerías como jQuery que traían una función para hacer más fáciles las peticiones, con $.ajax.

Más tarde salieron librerías como axios, o algunas otras que vienen incorporadas en frameworks.

Recientemente (bueno, hace ya algunos años, pero es más nueva que XMLHttpRequest) ha aparecido la función global fetch en JavaScript que trabaja con promesas y permite hacer peticiones HTTP de todo tipo de una manera fácil y rápida.

En este post voy a mostrar una guía de cómo trabajar con fetch en JavaScript para hacer peticiones GET, POST (con datos en el cuerpo), PUT y DELETE, además de solicitar HTML o JSON.

También veremos cómo enviar un formulario con fetch. Recuerda que ya vimos cómo subir un archivo usando fetch.

Anatomía de Fetch en JavaScript

Anatomía de fetch API en JavaScript – Peticiones HTTP y AJAX

Hay muchas maneras de invocar a fetch pero personalmente uso la que se muestra en la imagen. Recibe dos argumentos: una URL de la petición y un objeto de opciones.

En las opciones podemos especificar el método con method; si no se especifica se toma como si fuera GET.

Podemos agregar encabezados en headers en forma de clave valor.

El body es el cuerpo. Si trabajas con JSON, manda ahí lo que devuelva JSON.stringify, también puedes mandar una cadena o un FormData.

Fetch devuelve una promesa, pero en el then no trae los resultados parseados, debemos esperar el then e indicar el método de decodificación de los datos.

Si trabajas con JSON entonces devuelve resultadoRaw.json() (lo cual parseará el JSON automáticamente), si es un simple texto o HTML entonces resultadoRaw.text(), etcétera. (no olvides que debes hacer el return, para devolver de nuevo, una promesa)

Después de devolver la promesa, esperamos de nuevo el resultado, el cual ya viene parseado como lo hayamos indicado y ya podemos trabajar con él.

En el catch simplemente manejamos los errores; adicionalmente se podría definir un finally.

Nota: si no entiendes las funciones flecha mira este post.

Petición GET en JavaScript

Ahora que sabemos lo básico de fetch vamos a ver cómo descargar una página HTML:

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados");

$btnPeticion.addEventListener("click", () => {
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/")
  .then(resultadoRaw => {
   // Lo decodificamos como texto plano
   return resultadoRaw.text();
  })
  .then(resultadoComoTexto => {
   $resultados.textContent = resultadoComoTexto;
  });
});

La página podría ser cualquier otra (siempre y cuando sea del mismo dominio o tenga CORS). Como vamos a descargar el HTML solo necesitamos el texto. Al final el texto se coloca dentro de un párrafo.

Petición GET con JSON y fetch

Arriba descargamos un HTML pero también podemos consumir JSON:

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados");

$btnPeticion.addEventListener("click", () => {
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/get")
  .then(resultadoRaw => {
   // Lo decodificamos como json
   return resultadoRaw.json();
  })
  .then(resultadoComoJson => {
   // Aquí podemos acceder al objeto JSON
   // en este caso accedo a "headers.Origin"
   $resultados.textContent = resultadoComoJson.headers.Origin;
  });
});

En lugar de devolver resultadoRaw.text() devolvemos resultadoRaw.json()

La url que estoy solicitando devuelve un JSON, si tú programas el servidor asegúrate de usar JSON también.

Aquí hay un tutorial con PHP.

Petición POST con cuerpo JSON

Para enviar una petición POST indicamos el método y ponemos el cuerpo. En este caso enviaré JSON, así que en body estará lo que regrese el método stringify.

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados"),
 $inputNombre = document.querySelector("#inputNombre");

$btnPeticion.addEventListener("click", () => {
 const nombre = $inputNombre.value;
 if (!nombre) return alert("Escribe tu nombre");
 const objeto = {
  nombre: nombre,
  otroDato: "Otro valor :)",
 };
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/post", {
  method: "POST", // Indicar método POST
  body: JSON.stringify(objeto),// Con cuerpo
 })
  .then(resultadoRaw => {
   // Lo decodificamos como json
   return resultadoRaw.json();
  })
  .then(resultadoComoJson => {
   // Aquí podemos acceder al objeto JSON, httpbin
   // funciona como espejo y devuelve lo que se envía en
   // la clave data
   // Nota: se hace de nuevo JSON.parse porque devuelve
   // el JSON codificado
   const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
   $resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
   $resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
  });
});

Enviar formulario con fetch y FormData

Enviar un formulario es bastante sencillo, y evitamos que se recargue toda la página, cosa que se hace cuando se envía un formulario de manera nativa.

Solo hay que crear un FormData e invocar a append cuantas veces sea necesario, con dos argumentos: el nombre del campo (lo que iría en el atributo name del input) y el valor.

Al final, en body se envía el objeto de tipo FormData.

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados"),
 $inputNombre = document.querySelector("#inputNombre");

$btnPeticion.addEventListener("click", () => {
 const nombre = $inputNombre.value;
 if (!nombre) return alert("Escribe tu nombre");
 const fd = new FormData();
 fd.append("nombre", nombre);
 fd.append("otroValor", "Otro valor :)");
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/post", {
  method: "POST", // Indicar método POST
  body: fd,// Formulario
 })
  .then(resultadoRaw => {
   // Lo decodificamos como json
   return resultadoRaw.json();
  })
  .then(resultadoComoJson => {
   // Convertir a cadena
   $resultados.textContent = JSON.stringify(resultadoComoJson.form);
  });
});

No te confundas, una cosa es la petición y otra la respuesta. La url con la que estoy probando (que es como un espejo, httpbin) devuelve un JSON con toda la información recibida, por eso decodifico la respuesta como JSON, pero la petición se fue como un FormData.

Petición PUT y DELETE

Estas peticiones son similares a la petición POST. Si vas a enviar parámetros en la URL simplemente concatena.

La petición PUT queda así:

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados"),
 $inputNombre = document.querySelector("#inputNombre");

$btnPeticion.addEventListener("click", () => {
 const nombre = $inputNombre.value;
 if (!nombre) return alert("Escribe tu nombre");
 const objeto = {
  nombre: nombre,
  otroDato: "Otro valor :)",
 };
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/put", {
  method: "PUT", // Indicar método PUT
  body: JSON.stringify(objeto),// Con cuerpo
 })
  .then(resultadoRaw => {
   // Lo decodificamos como json
   return resultadoRaw.json();
  })
  .then(resultadoComoJson => {
   // Aquí podemos acceder al objeto JSON, httpbin
   // funciona como espejo y devuelve lo que se envía en
   // la clave data
   // Nota: se hace de nuevo JSON.parse porque devuelve
   // el JSON codificado
   const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
   $resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
   $resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
  });
});

La petición DELETE queda así:

const $btnPeticion = document.querySelector("#btnPeticion"),
 $resultados = document.querySelector("#resultados"),
 $inputNombre = document.querySelector("#inputNombre");

$btnPeticion.addEventListener("click", () => {
 const nombre = $inputNombre.value;
 if (!nombre) return alert("Escribe tu nombre");
 // Nota: en algunas ocasiones no es posible (por parte del servidor)
 // recibir datos en una petición DELETE
 const objeto = {
  nombre: nombre,
  otroDato: "Otro valor :)",
 };
 $resultados.textContent = "Cargando...";
 fetch("https://httpbin.org/delete", {
  method: "DELETE", // Indicar método DELETE
  body: JSON.stringify(objeto),// Con cuerpo
 })
  .then(resultadoRaw => {
   // Lo decodificamos como json
   return resultadoRaw.json();
  })
  .then(resultadoComoJson => {
   // Aquí podemos acceder al objeto JSON, httpbin
   // funciona como espejo y devuelve lo que se envía en
   // la clave data
   // Nota: se hace de nuevo JSON.parse porque devuelve
   // el JSON codificado
   const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
   $resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
   $resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
  });
});

Conclusión

En algunos ejemplos no manejo los errores con catch ni finally, lo hice así para simplificar el código. Recuerda que siempre puedes enviar el tipo de dato que quieras, ya sea un formulario, un JSON, una cadena o cualquier otra cosa.

No olvides que la petición y la respuesta (así como el tipo de dato que regresan) son cosas distintas.

En este caso probé con un servidor que respondía con JSON pero podría devolver texto plano u otras cosas, todo depende de nuestra situación.

Aquí dejo algunas referencias en donde puedes encontrar más información sobre la API de fetch.

https://developer.mozilla.org/es/docs/Web/API/Request/headers

https://developer.mozilla.org/es/docs/Web/API/Body

https://developer.mozilla.org/es/docs/Web/API/Fetch_API

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Hola estimado gracias por el aporte, quisiera saber si tienes información de como hacer una petición con fetch y consumir un metodo especifico en php, agradezco toda la información que puedas suministrarme

  • Excelente la explicación entendí cosas de fetch que no había entendido, pero al tratar de hacer lo mismo enviando información a un bd me genera un error que es "Uncaught (in promise) SyntaxError: Unexpected token {
    // Lo decodificamos como json
    return resultadoRaw.json();
    })
    .then(resultadoComoJson => {
    // Convertir a cadena
    $resultados.textContent = JSON.stringify(resultadoComoJson.form);
    });

    Si me puedes ayudar te agradecería, se que el error es porque no esta devolviendo un json pero no se porque, lo estoy trabajando con el MVC pero si no tengo el MVC tambien sale el mismo error.

    Esta es el html o la vista

    !DOCTYPE html>

    Document

    #resultados{
    width:50%;
    height:80px;
    background:red;
    }

    y este es el controlador

    cliente($documento,$nombre,$apellido,$correo,$celular,$sexo,$fecha);

    echo "los datos fueron ". $datos;

    }

    require_once('vista/vistacliente.php');

    • Hola, gracias por tus comentarios. Veo que usas PHP, debes hacer un echo json_encode para codificar los datos como JSON incluso si es una simple cadena.
      Por otro lado, si no te funciona JSON, en el resultadoRaw puedes hacer un:
      return resultadoRaw.text()
      Para que lo decodifiques como texto y veas lo que está pasando.
      No olvides seguirme y compartir.
      Saludos :)

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

6 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

6 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

6 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

6 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

6 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

7 días hace

Esta web usa cookies.