Usando fetch para enviar solicitudes HTTP en JavaScript

Durante el desarrollo de software, las solicitudes HTTP se realizan todo el tiempo. Exploraremos la API Fetch: un enfoque moderno basado en promesas para las solicitudes HTTP.

Introducción

La API Fetch de JavaScript nos permite enviar solicitudes HTTP. Ha sido una parte estándar de JavaScript desde que se introdujo ECMAScript 2015 (comúnmente conocido como ES6) y usa Promises.

Este artículo primero le mostrará cómo se realizaron las solicitudes con JavaScript estándar antes de que se desarrollara la API Fetch. Luego lo guiaremos sobre cómo usar la API Fetch, destacando la mejora que representa con respecto a otros métodos.

Configuración

Este artículo analiza el uso de la API Fetch para realizar solicitudes HTTP en el navegador. Como tal, necesitamos configurar una página HTML que nuestro navegador pueda mostrar. En su espacio de trabajo, comience creando un archivo index.html.

El archivo index.html se utilizará a lo largo del artículo. La página HTML no tiene contenido textual, solo se usará para cargar los archivos JS para que podamos ver las solicitudes y respuestas en la consola de nuestro navegador:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>JavaScript HTTP Requests</title>
</head>

<body>
    <script src="./xhr.js"></script>
</body>

</html>

Cambiaremos la etiqueta script cuando estemos aprendiendo nuevos temas, pero el resto del HTML permanecerá igual.

También desea tener abierta la consola de su navegador para que podamos ver los resultados de nuestras solicitudes HTTP. Esto generalmente se hace haciendo clic derecho en la página web y seleccionando "Inspeccionar". En Chrome se ve así:

La opción de menú \"Inspeccionar\" al hacer clic derecho en Chrome

Ahora, seleccionemos la pestaña "Consola" para que podamos ver cualquier resultado que registre nuestro JavaScript:

La pestaña \"Consola\" en nuestra Developer Console

¡Estás listo! Comencemos a enviar solicitudes HTTP con el primer método posible con JavaScript: XMLHttpRequest.

Solicitudes con XMLHttpRequest

Antes de que existiera Fetch API, todas las solicitudes de JavaScript se realizaban con un objeto XMLHttpRequest (o XHR). A pesar de su nombre, este objeto puede recuperar datos en cualquier formato de un servidor. No se limita solo a XML.

Pongámonos manos a la obra con una solicitud XHR en nuestro navegador. En la misma carpeta que su archivo index.html, cree un nuevo archivo xhr.js.

Este nuevo archivo JavaScript creará un objeto XHR y enviará una solicitud GET a una API JSON. Luego registraremos los resultados de la solicitud en la consola. En su archivo xhr.js, ingrese lo siguiente:

1
2
3
4
5
6
7
let xhr = new XMLHttpRequest();
xhr.open('get', 'https://jsonplaceholder.typicode.com/posts/1');
xhr.send();

xhr.onload = function() {
    console.log(xhr.response);
};

En la primera línea, creamos un nuevo objeto XMLHttpRequest. Luego usamos el método open() para crear una nueva solicitud HTTP. El primer argumento de open() es el método HTTP de la solicitud; en este caso, estamos enviando una solicitud GET. El segundo argumento es la URL con el recurso del servidor que queremos. Luego usamos el método send() para enviar la solicitud.

Cuando un ‘XHR’ obtiene datos de la red con éxito, envía un evento de carga. Para procesar los datos después de cargarlos, establecemos una función en la propiedad onload del objeto XHR. En este caso, simplemente registramos la respuesta en la consola.

Ahora, en su consola de desarrollador debería ver lo siguiente.

Salida JSON de la solicitud XHR para publicaciones de blog

¡Buen trabajo al realizar una solicitud de API con XMLHttpRequest!

Si bien es útil, la forma en que maneja los datos asincrónicos es muy diferente de las promesas organizadas y estandarizadas que se usan en JavaScript moderno. Podemos mantener código más fácil con Fetch API.

La API de búsqueda

Fetch API es una API basada en promesas para realizar solicitudes HTTP, similar a lo que hicimos con XMLHttpRequest. A diferencia de XMLHttpRequest, no tenemos que crear nuevos objetos cuando usamos la API Fetch. Los navegadores vienen con una función fetch() global que podemos usar para hacer solicitudes.

Veamos cómo podemos usar esta API para realizar solicitudes HTTP a través de Internet.

Envío de solicitudes con recuperación

La Fetch API puede realizar GET, POST, PUT, PATCH, DELETE y [otros tipos de solicitudes HTTP](https://developer.mozilla.org/en-US/docs/Web /HTTP/Métodos). Nos centraremos en dos de los métodos más comunes utilizados en las solicitudes HTTP: GET y POST.

Solicitudes GET

Usemos la API Fetch para hacer una solicitud GET a https://jsonplaceholder.typicode.com/posts/1 como hicimos con XMLHttpRequest antes.

En su archivo index.html, cambie la etiqueta script para hacer referencia a un nuevo archivo JavaScript:

1
<script src="./fetchGet.js"></script>

Ahora cree el nuevo archivo fetchGet.js en el mismo espacio de trabajo. Enviaremos una solicitud GET y registraremos la salida en la consola una vez más. Ingrese el siguiente código en fetchGet.js:

1
2
3
fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(response => response.json())
    .then(json => console.log(json));

En la primera línea usamos la función global fetch() para enviar una solicitud GET a nuestra API. El argumento de fetch() es la URL con el recurso del lado del servidor.

Luego encadenamos la promesa con el método then(), que captura la respuesta HTTP en el argumento response y llama a su método json(). El método json() analiza el cuerpo de la respuesta en un objeto JSON. Sin embargo, lo devuelve como una promesa.

Por eso usamos then() una vez más para encadenar otra promesa, que registra el JSON analizado en la consola.

Vuelva a cargar index.html si es necesario para que pueda ver el siguiente resultado:

Salida JSON de la solicitud de fetch para publicaciones de blog

Nota: El resultado se vería diferente a lo que obtuvimos cuando hicimos la solicitud GET con XMLHttpRequest. Eso es porque XMLHttpRequest devuelve los datos de respuesta HTTP como una cadena, mientras que analizamos los datos en un objeto JSON. Si bien los formatos devueltos son diferentes, su contenido es el mismo.

Veamos cómo podemos usar fetch() para enviar datos en una solicitud POST.

Solicitudes POST

Podemos cargar datos con fetch() agregando un objeto JavaScript como su segundo argumento con la información requerida para enviar la solicitud HTTP.

Usemos fetch() para cargar datos JSON en la solicitud POST a una API simulada. En su archivo index.html, cambie la etiqueta script para hacer referencia a un nuevo archivo JavaScript:

1
<script src="./fetchPost.js"></script>

Ahora cree fetchPost.js en su espacio de trabajo para que podamos realizar una solicitud POST a la API que cargará un nuevo elemento pendiente como un objeto JSON. Escribe el siguiente código en fetchPost.js:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const todo = {
    title: 'Some really important work to finish'
};

fetch('https://jsonplaceholder.typicode.com/todos', {
        method: 'POST',
        body: JSON.stringify(todo),
        headers: {
            'Content-type': 'application/json; charset=UTF-8'
        }
    })
    .then(response => response.json())
    .then(json => {
        console.log(json);
    });

Lo primero que hacemos es crear un objeto todo, que contiene los datos que nos gustaría enviar a la API.

Al igual que con las solicitudes GET, usamos fetch() proporcionando una URL de la API a la que queremos llegar. Sin embargo, esta vez tenemos un objeto como segundo argumento para fetch() con las siguientes propiedades:

  • método: una cadena que especifica con el método HTTP para usar en la solicitud
  • cuerpo: Una cadena con cualquier dato que queremos dar al servidor en nuestra solicitud
  • headers: un objeto que nos permite agregar los encabezados que queremos que incluyan nuestras solicitudes HTTP

Al igual que con la solicitud GET, procesamos la respuesta del servidor como JSON y la registramos en la consola del desarrollador. Recargar nuestro index.html debería mostrarnos la siguiente salida de la consola:

Salida JSON de la solicitud Fetch POST para agregar un nuevo elemento \"todo\"

¡Excelente trabajo usando fetch() para cargar datos a través de la solicitud POST!

Ahora que sabemos cómo hacer varias solicitudes HTTP con Fetch API, veamos cómo podemos manejar diferentes respuestas HTTP.

Procesando respuestas con Fetch

Hasta ahora, hemos estado analizando los datos de respuesta a JSON. Si bien esto funciona con la API utilizada en el ejemplo, otra respuesta puede devolver diferentes tipos de datos que no son JSON.

Un objeto de respuesta HTTP que se devuelve después de una solicitud fetch() exitosa se puede analizar en varios formatos. Además del método json(), podemos usar lo siguiente:

  • text(): Devuelve la respuesta como datos de cadena
  • blob(): Devuelve la respuesta como objeto blob (datos binarios junto con su codificación)
  • formData(): devuelve la respuesta como objeto FormData (que almacena pares clave-valor de datos de cadena)
  • arrayBuffer(): Devuelve la respuesta como ArrayBuffer (representación de bajo nivel de datos binarios)

Al igual que el método json(), estas funciones devuelven una promesa con el contenido. Por lo tanto, todos deben estar encadenados con una función then() para que el contenido pueda ser procesado.

Estas funciones se utilizan para procesar respuestas HTTP correctas que devuelven datos. Veamos ahora cómo podemos manejar los errores con la API Fetch.

Manejo de errores HTTP

Al igual que con cualquier otra promesa, los errores fetch() se manejan en el método catch() que se coloca al final de una cadena de promesa. Sin embargo, la función catch() solo se usa si fetch() no pudo enviar una solicitud. Esto generalmente significa que hubo un error de red.

Si intentamos acceder a una URL que no existe y el servidor devuelve un 404, no quedaría atrapado en el método catch(), ya que 404 es un estado de respuesta HTTP válido.

Por lo tanto, al manejar errores con Fetch API, debemos hacer dos cosas:

  • Incluya la cláusula catch() al final de la cadena de promesas para detectar cualquier error de red
  • Verifique el código de estado HTTP de la respuesta para ver si tuvo éxito o no.

Hagamos otro ejemplo donde tratamos de obtener una URL que no existe.

Usando nuestro ejemplo de solicitud GET, podemos usar catch() así:

1
2
3
4
fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(err => console.error(err));

Sin embargo, la función catch() solo se usa si no se pudo enviar la solicitud fetch(). En su archivo index.html, cambie la etiqueta del script para hacer referencia a un nuevo archivo JavaScript:

1
<script src="./fetchError.js"></script>

Ahora, en su espacio de trabajo, cree un nuevo archivo fetchError.js. Introduce el siguiente código:

1
2
3
4
5
6
7
8
9
fetch("https://jsonplaceholder.typicode.com/notreal/")
    .then(response => {
        if (!response.ok) {
            throw new Error("Could not reach website.");
        }
        return response.json();
    })
    .then(json => console.log(json))
    .catch(err => console.error(err));

Comenzamos enviando una solicitud GET a una URL inexistente en esa API. Tenga en cuenta el cambio en la primera función then() que analiza el cuerpo de la respuesta a JSON:

1
2
3
if (!response.ok) {
    throw new Error("Could not reach website.");
}

Comprobamos la propiedad ok, que es booleana. Es verdadero si el código de estado HTTP de la respuesta está entre 200 y 299. Al usar el operador no (!), podemos capturar los casos en los que el servidor devolvió un error HTTP. Si recibimos un error HTTP, lanzamos un error personalizado que terminaría la cadena de promesa fetch().

Si no recibimos un error HTTP, devolvemos la respuesta JSON como una promesa, como antes.

Al final de la cadena de promesas, tenemos una función catch(), que simplemente registra el error en la consola.

Si vuelve a cargar su página index.html, debería ver esta salida de la consola:

Salida de error al intentar llegar a una URL falsa

Bien hecho, cubriste los fundamentos de Fetch API.

Conclusión

La API Fetch proporciona una forma basada en promesas de enviar solicitudes HTTP en JavaScript. Debido a que está basado en promesas, los desarrolladores lo ven como un reemplazo más limpio de XMLHttpRequest.

Con la función fetch(), podemos realizar solicitudes GET y POST a diferentes URL. Podemos configurar solicitudes fetch() para usar cualquier método HTTP que queramos usar.

La función fetch() también proporciona un objeto de respuesta que se puede analizar en varios formatos. Estos incluyen JSON, texto y bytes, por nombrar algunos.

También vimos cómo podemos manejar los errores al realizar solicitudes con fetch(). Además de colocar el método catch() al final de la cadena de promesas para detectar errores de red, también debemos verificar el código de estado de la respuesta HTTP que recibimos antes de analizar sus datos.

Fetch API hace que las llamadas API externas sean manejables sin el uso de bibliotecas externas. ¿A qué API planea acceder con fetch()? tch()`?