Usando la API FETCH para hacer llamadas AJAX - Una promesa cumplida

Actualizaciones parciales de las páginas web usando promesas cumplidas

by Iveta Karailievova Date: 26-12-2020 ajax fetch promise javascript

En este artículo hablamos sobre lo que son las llamadas AJAX y cómo utilizarlas de forma tradicional, utilizando el objeto XMLHttpRequest (XHR). En resumen, gracias a las llamadas AJAX una página web puede ser parcialmente actualizada sin tener que recargar todo el contenido. Esto conlleva una mejor velocidad de carga, usabilidad y hoy en día es una parte indispensable del desarrollo web moderno. Ahora nos centraremos en un enfoque más moderno, que es el uso de la web API fetch. En este artículo construiremos una funcionalidad que genere y muestre en nuestra página personajes aleatorios de Rick y Morty (estoy segura de que la mayoría de los nerds conocéis bastante bien la serie, pero para los que no, os la recomiendo mucho).  El único lenguaje que necesitamos usar es JavaScript básico (también llamado "vanilla"), y el resto de la magia (la parte de atrás) será proporcionada por la Rick and Morty REST API

Las Web APIs - ¿qué son?

Una API Web es una interfaz de programación de aplicaciones para la Web. En otras palabras, cuando se escribe código para una página web, se puede utilizar una  web API, que facilita el trabajo, por ejemplo, proporcionando al navegador web más funcionalidad, simplificando funciones complejas o simplificando la sintaxis del código. Una de esas web APIs útiles es fetch, que nos ayuda a realizar solicitudes web de una forma más intuitiva y sencilla.

¿Qué es la fetch API y por qué es mejor que XHR?

Es una API de JavaScript nativa y relativamente nueva. Fetch API fue introducida con ECMAScript 6, también conocido como ES6 y ECMAScript 2015, que fue la segunda gran revisión de JavaScript. 

Fetch permite hacer peticiones asincrónicas de red a servidores web similares a la XMLHttpRequest, pero con la ventaja de que el código es más elegante, más simple y más limpio. La principal diferencia entre el API de XHR y fetch es que el API de Fetch utiliza promesas (promises en inglés). Gracias a esto, no tendremos que lidiar con las funciones de tipo callback y el infierno llamado callbackhell en el cual potencialmente podrían resultar. Además, con XMLHttpRequest, la sintaxis que necesitamos usar en nuestro código es más compleja y, por lo tanto, podría dar lugar a errores. Podemos decir sin duda que fetch API es una mejora sobre el método tradicional XMLHttpRequest, y también nos ofrece más funcionalidades.

Aunque es soportado por la mayoría de los navegadores de hoy en día, no es soportado por Internet Explorer. Por lo tanto, si necesitas que tu código sea compatible con IE, deberías considerar el uso de polyfills. Estos son básicamente piezas de código JavaScript responsables de proporcionar una funcionalidad moderna en los navegadores más antiguos que no lo soportan de forma nativa.

Cómo usar fetch - un ejemplo donde obtendremos datos de un API

Como su nombre en inglés lo indica, la API de fetch proporciona una interfaz para buscar, obtener recursos. Para llamar al método fetch, necesitamos proporcionar un argumento - la URL o ruta del recurso del que queremos obtener nuestra respuesta. 

Seamos prácticos y empecemos a preparar nuestro ejemplo. Aquí está el código HTML:

En nuestro archivo index.html, ponemos dentro el elemento <body>:

<main>
<label for="number">Choose a number</label><br>
<input id="number" type="number" min="1" max="671" />
<figure>
<img id="avatar" src="" alt="" />
</figure>
</main>

y para hacerlo un poco más atractivo, algo de CSS:

body {
background-color: coral;
color: grey;
font-size: xx-large;
text-transform: uppercase;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

La siguiente parte - nuestro código vanilla JavaScript con el método fetch

Empecemos con la parte fácil: crear constantes para acceder a los elementos DOM que vamos a necesitar:

// el inputValue nos permite acceder al valor de la entrada del usuario, es decir, el número elegido
const inputValue = document.getElementById('number')
// esta constante nos permite establecer la imagen a mostrar, cambiando dinámicamente su atributo "src"
const avatar = document.getElementById('avatar') 

Ya que queremos ser capaces de acceder a diferentes caracteres, por lo que mantenemos la parte de identificación flexible - utilizando el método replace(). Proporcionaremos el número de "id" dinámicamente, cuando el usuario cambie el valor de la forma de entrada.

const API_URL = 'https://rickandmortyapi.com/api/character/:id'
const URL = API_URL.replace(':id', id)
fetch(URL)

And now the intY ahora la parte interesante... el método fetch devuelve una promesa.

¿Qué es una promesa de JavaScript? 


Las promesas son un método moderno, una solución a los problemas que conllevan las funciones de tipo callback. Una promesa es un sustituto de un valor que será obtenido en el futuro, cuando se resuelva la petición asincrónica. A esta promesa, podemos adjuntar handlers, para que se lleve a cabo cierta acción en el caso de que la promesa se cumpla y otra si la promesa es rechazada.

También se podría pensar que una promesa es en cierto modo similar a un evento, pero con la diferencia de que una promesa sólo puede tener éxito o fracasar una vez, y que el resultado es definitivo, lo que significa que no puede pasar de ser cumplida a ser rechazada o viceversa. 

En nuestro caso, la promesa contendrá en algún momento en el futuro la respuesta, más precisamente un objeto de respuesta, una respuesta HTTP. Pero cuidado, para poder trabajar con los datos reales que recibimos de la API, primero tenemos que extraer el cuerpo de la respuesta, utilizando el método json(). De esta manera, analizamos la respuesta en JSON. Pero, y esto puede parecer algo confuso, el método json() devuelve otra promesa. Esto se debe a que la lectura del flujo que contiene la respuesta está sucediendo también de forma asincrónica.

Trabajamos con las promesas asignándoles handlers, en concreto los métodos then() y catch().

Las promesas pueden asumir uno de los siguientes estados:

  • pending (pendiente) - este estado se asigna automáticamente después de que la promesa se crea, significa que hasta ahora la promesa no se cumplió ni se rechazó;

    fulfilled (cumplida) - la promesa ha sido completada con éxito y el resultado que obtenemos es el valor de la operación;

    rejected (rechazada) - la promesa no se ha completado con éxito y el resultado que obtenemos es la razón por la que esto ocurrió (el error);

Gestión de errores al usar fetch

En el caso del método fetch, las promesas fetch son rechazadas sólo cuando se encuentra un error de red (como problemas de permisos, CORS mal configurado en el lado del servidor, fallo en la búsqueda de DNS, etc.) Las respuestas HTTP con los códigos 4xx y 5xx no son errores de red, por lo que la catch() adjuntado a la promesa no se disparará en el caso de este tipo de errores. Por eso necesitamos comprobar la propiedad "ok" de la respuesta del método fetch. Se puede hacer de la siguiente manera:

if(response.ok)

devuelve un valor booleano, siendo cierto si la respuesta se devuelve con éxito.

Al agregar la siguiente función de manejo de errores, podemos asegurarnos de que nuestros errores son lanzados y capturados correctamente, como en el caso de que el usuario elija un id que esté fuera del rango de caracteres de la API:

function handleErrors (response) {  
  if (response.ok) {
return response
}
   throw new Error(response.statusText) 
}   

Así que, ahora tenemos que encadenar todos los métodos then() de nuestras promesas, como así:

function getCharacter (id) {
  const URL = API_URL.replace(':id', id)
  fetch(URL)
  // primero adjuntamos la función de manejo de errores
    .then(handleErrors)
// A continuación, si no hubo ningún error, usamos el método json en nuestro objeto de respuesta
    .then(function (response) {
      console.log(response)
      return response.json()
    })
    // ya que el método response.json() usado en un objeto Response devuelve otra promesa, adjuntamos otro metodo then a los datos que recibimos
    .then(function (data) {
      const newCharacterJSON = data
      // al analizar la estructura de los datos de respuesta, sabemos que necesitamos acceder a la llave "image" del objeto JSON para obtener el URL de la imagen
      var imagePath = newCharacterJSON.image
      // ahora establecemos el atributo src de nuestro elemento de imagen como la URL de la respuesta
      avatar.setAttribute('src', imagePath)
    })
    //  esta parte del código nos permite capturar correctamente los errores que podrían haber aparecido, tanto los errores de la promesa original que se rechazó, así como los errores que son lanzados por nuestra función de manejo de errores
    .catch(function (err) {
      console.log('Something went wrong!', err)
    })
}

Nota: la respuesta que obtenemos no es JSON, sino un objeto con una serie de métodos que se pueden utilizar dependiendo de lo que se quiera hacer con la información. Dado que la API de Rick y Morty que estamos usando nos devolverá JSON, la respuesta devuelta tendrá el método .json(). Sólo tenemos que llamar a .json() en la variable de respuesta.

Y finalmente, necesitamos pensar en una forma de llamar a la función. Lo hacemos añadiendo un listener de eventos a nuestro elemento de entrada. En este ejemplo elegimos usar el evento change, que se dispara cada vez que el valor del campo de entrada se cambia.

inputValue.addEventListener('change', function () {
const choosenNumber = inputValue.value
getCharacter(choosenNumber)
})

Para poder observar mejor este ejercicio, aquí puede ver el código completo y una demostración de su funcionamiento.

Conclusión

Aunque los resultados que estamos obteniendo pueden parecer los mismos, el uso de fetch API en vez del XMLHttpRequest parece ser la forma correcta de escribir nuestro código en el futuro, porque nos permite manejar las respuestas de una forma más organizada y nos ahorra el problema de descender a nuestro pequeño infierno de llamadas de tipo callback (al temido callbackhell).

 
by Iveta Karailievova Date: 26-12-2020 ajax fetch promise javascript visitas : 3873  
 
Iveta Karailievova

Iveta Karailievova

Originally coming from a marketing background, decided to turn her life around and immerse herself into the wonderful exciting and most importantly – never boring world of technology and web development. Proud employee at MA-NO . Easily loses track of time when enjoying working on code. Big fan of Placebo, cats and pizza.

 
 
 

Artículos relacionados

Por qué los desarrolladores de JavaScript deberían preferir Axios a Fetch

Por qué los desarrolladores de JavaScript deberían preferir Axios a Fetch En mi artículo anterior, "Usando la Api Fetch Para Hacer Llamadas Ajax", hablé de los fundamentos de la API Fetch.…

Haciendo peticiones AJAX a una REST API usando vanilla JavaScript y XHR

Imagina que acabas de construir tu primera página web estática y te gustaría añadir alguna funcionalidad para hacerla más atractiva y generalmente más utilizable. Tal vez te gustaría entretener al…

Async/Await como funcionan realmente: un ejemplo

Las Promises nos dan una manera más fácil de tratar secuencialmente la asincronía en nuestro código. Esta es una adición bienvenida, dado que nuestros cerebros no están diseñados para tratar…