> Manuales > Manual de Ajax práctico

Tutorial de fetch, el API de Javascript para las comunicaciones asíncronas basado en promesas. Es la manera más sencilla y práctica de hacer Ajax con código nativo en el navegador. Ejemplos de fetch en Javascript para el navegador.

Fetch de Javascript

Fetch es un nuevo API (ya no tan nuevo) para el acceso a recursos del servidor de manera asíncrona, basado en promesas. Es básicamente la nueva interfaz de programación para realizar funcionalidades Ajax con Javascript, que ya podemos usar en cualquier navegador. Fetch tiene diversas ventajas entre las que podemos destachar la posibilidad de una mejor organización del código en nuestras funcionalidades Ajax, ya que está basado en promesas.

En el artículo de Fetch vamos a tratar diversos temas de interés dedicados al trabajo con solicitudes Ajax:

Qué es Ajax

El acceso a recursos de un servidor de manera asíncrona, comúnmente llamado Ajax, nos permite realizar solicitudes HTTP sin necesidad de recargar toda la página.

Esta es una funcionalidad que se usa mucho en la actualidad, ya que ofrece una mejora significativa de la experiencia de usuario en las aplicaciones web frontend. Además, permite una separación más patente entre el código del frontend y el código del backend, algo deseable de cara al mantenimiento de las aplicaciones en general y que es muy común en las aplicaciones web modernas.

Tradicionalmente Ajax en Javascript se realizaba con en objeto XMLHttpRequest, sin embargo este objeto tenía un par de desventajas:

Para mejorar la compatibilidad de navegadores y poder hacer una programación de más alto nivel los desarrolladores acababan usando alguna herramienta de terceros, como es el caso de una librería como jQuery para acceder a las funcionalidades de Ajax.

Fetch en Javascript

Fetch ofrece una nueva interfaz estándar de uso de Ajax para el desarrollo frontend, a la vez que permite usar promesas, que nos facilitan la organización del código asíncrono en las aplicaciones. Es un mecanismo disponible actualmente en todos los navegadores, exceptuando los viejos Internet Explorer.

Sin embargo, aunque tuviéses que programar todavía con soporte para Internet Explorer, podrías usar igualmente fetch solo con la instalación del correspondiente polyfill. Esto es un tema de otro artículo: Polyfill para Fetch.

En este tutorial de fetch veremos unos primeros ejemplos sencillos con Fetch y más adelante hablaremos de usos más avanzados, como el acceso a las API REST. Lo que no vamos a explicar es el uso de las promesas de Javascript ES6, ya que ha sido materia de estudio de artículos anteriores. Tampoco vamos a tratar todavía sobre el uso de sus Polyfill y sus diferentes alternativas para compatibilidad, que analizaremos en breve en futuros artículos.

Método fetch

El método fetch() depende directamente del objeto window del navegador. Su uso más simple consiste en pasarle una URL, cuyo contenido se traerá el cliente web de manera asíncrona.

Nota: Como toda la jerarquía de objetos del navegador comienza en window, podemos opcionalmente invocar a fetch sin mencionar al objeto window.
fetch('test.txt')

La URL a la que estamos accediendo es "test.txt", una URL relativa que supondrá que en nuestro servidor disponemos de un archivo llamado "test.txt" en la misma carpeta donde está la página donde estamos trabajando.

Como ya hemos dicho, fetch basa su trabajo en promesas ES6, por lo que nos devolverá una promesa que podemos tratar tal como estamos acostumbrados a hacer, con el "then" y el "catch".

fetch('test.txt')
  .then(ajaxPositive)
  .catch(showError);

Como sabes, then() nos servirá para definir la función que se encargará de realizar acciones en el caso positivo y catch() para definir una función con código a ejecutar en el caso negativo.

Tratamiento del error con catch()

Comenzamos por ver el código a ejecutar en el caso negativo, que es más sencillo. Simplemente definimos una función que recibirá como parámetro el motivo del error.

function showError(err) { 
  console.log('muestor error', err);
}
Nota: Fíjate que la función showError() fue enviada como parámetro en el catch().

Es muy importante mencionar que fetch(), así como en general todo el trabajo con Ajax, se implementa mediante el protocolo HTTP. Es por ello que, para asegurarnos que los ejemplos con fetch funcionen, tenemos que acceder a la página web que realiza esa solicitud con fetch por medio de HTTP. Es decir, no podríamos simplemente hacer un doble clic sobre un archivo .html y abrir el documento en el navegador con file://. En resumen, debemos necesariamente tener el archivo .html en un servidor web y acceder a él mediante http://.

Si la página desde la que se hace el fetch se accede desde file:// observaremos como la llamada Ajax nos da un error y el flujo de ejecución de nuestro código se va por la parte del catch.

Tratamiento del caso positivo con then()

Cuando se ejecuta la solicitud de manera correcta podemos escribir el código del caso positivo en la función que asignamos al then() asociado al método fetch().

El caso positivo siempre nos devolverá una respuesta del servidor, sobre la que se pueden realizar varias cosas, básicamente saber los detalles derivados del protocolo HTTP de la respuesta y acceder al contenido que el propio servidor nos ha enviado.

La respuesta del servidor la recibimos como parámetro en la función que indicamos para ejecutar en el caso positivo, then(). La respuesta contiene varias propiedades y métodos que podemos usar para realizar diferentes acciones y examinar lo que el servidor nos devolvió. En el siguiente código encontramos un uso básico de ese objeto de respuesta.

Nota: Ten en cuenta que recibir esta respuesta no nos asegura que la solicitud HTTP se completase correctamente. Podría darse el caso que intentamos acceder a un recurso no existente y entonces recibiremos la respuesta, aunque con un código 404 de página no encontrada. Es decir, la respuesta que estamos recibiendo en el then() puede tener, o no, el contenido que estábamos requiriendo. Así que antes de nada tendremos que analizar la respuesta para ver si está o no correcta.
function ajaxPositive(response) {
  console.log('response.ok: ', response.ok);
  if(response.ok) {
    response.text().then(showResult);
  } else {
    showError('status code: ' + response.status);
    return false;
  }
}
Nota: Fíjate que la función ajaxPositive() fue enviada como parámetro en el then() asociado al fetch. Primer código de este artículo.

Por ejemplo, la propiedad "ok" de la respuesta nos ofrece información sobre si la solicitud produjo una respuesta con un código positivo (un status 200 o similar) en el protocolo HTTP. La propiedad "status" nos ofrece el código de respuesta del servidor (200, 404, 500, etc.).

Si quieres saber más sobre el la propiedad status del objeto response puedes leer esta faq: Cómo obtener el código de respuesta HTTP del servidor a una solicitud Ajax con Fetch.

Acceder al texto de la respuesta de Ajax con fetch

El método que nos devuelve el texto del servidor se llama text(). Es un método existente en el objeto de la respuesta recibida. Sin embargo, acceder al contenido de la respuesta, el texto que el servidor nos envía, no es tan trivial. El motivo es que el método text() devuelve otra promesa, lo que nos obliga a tratarla de nuevo con el correspondiente then / catch.

En nuestro código anterior solo estamos tratando el caso positivo, asociando la función "showResult", que será la que se ocupe de ejecutar código cuando el texto de la respuesta ya esté disponible.

La función que asocias al "then" del método text() de la respuesta recibe como parámetro el contenido de texto recibido por el servidor. En nuestro caso habíamos asociado "showResult" y en el código de esa función es donde podremos ver cómo usar el texto de la respuesta.

function showResult(txt) {
  console.log('muestro respuesta: ', txt);
}

Mejora del código mediante arrow functions

Si usamos las funciones flecha (arrow functions) de Javascript conseguimos un código mucho más compacto. Todo navegador que soporta fetch también soporta las funciones flecha, por lo que puedes usarlo sin problema alguno y, en todo caso, también puedes traspilar el código para aportar soporte a navegadores antiguos.

Aquí puedes ver lo compacto que podría llegar a ser todo el código de acceso a un archivo de texto cuyo contenido hemos recuperado mediante fetch.

fetch('file-to-read.txt')
  .then( response => response.text() )
  .then( resultText => console.log(resultText) )
  .catch( err => console.log(err) );

Ejemplo completo de Ajax con fetch

Para entender mejor un uso completo de uso de fetch encontrarás ahora el código del ejercicio que hemos usado como base para escribir este artículo.

Por simplificarlo bastante, todos los mensajes de respuesta los enviamos a la consola, por lo que tendrás que abrirla para observar la salida del programa.

<!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>Fetch</title>
</head>
<body>
  <button id="btn">Hacer una conexión con Ajax</button>
  
  <script>
  document.addEventListener('DOMContentLoaded', configureAjaxCalls);

  function configureAjaxCalls() {
    document.getElementById('btn').addEventListener('click', function() {
      fetch('test.txt')
        .then(ajaxPositive)
        .catch(showError);
    });

    function ajaxPositive(response) {
      console.log('response.ok: ', response.ok);
      if(response.ok) {
        response.text().then(showResult);
      } else {
        showError('status code: ' + response.status);
      }
    }

    function showResult(txt) {
      console.log('muestro respuesta: ', txt);
    }

    function showError(err) { 
      console.log('muestor error', err);
    }
  }
  </script>
</body>
</html>

Esperamos que entiendas este código y puedas experimentar por ti mismo las funcionalidades detrás del acceso a Ajax con fetch. En siguientes artículos profundizaremos un poco más sobre este mecanismo del navegador.

Acceso a un API REST mediante fetch

Por supuesto, con fetch podemos acceder a los servicios web y recuperar datos que nos ofrece un API REST. El mecanismo es muy similar a lo que hemos aprendido en este artículo hasta el momento, con la única diferencia que tendremos que comprobar la respuesta de nuestro API para saber si la conexión ha sido satisfactoria.

Con fetch podemos hacer todo tipo de conexiones HTTP. Vamos a ver un ejemplo sobre una solicitud a un API mediante GET, para recuperar datos.

fetch('https://randomuser.me/api/?results=10')
  .then( response => {
    if(response.status == 200) {
      return response.text();
    } else {
      throw "Respuesta incorrecta del servidor" 
    }
  })
  .then( responseText => {
    let users = JSON.parse(responseText).results;
    console.log('Este es el objeto de usuarios', users);
  })
  .catch( err => {
    console.log(err);
  });

Como puedes comprobar, accedemos a una URL de un servicio web. Éste nos entrega una lista de usuarios aleatorios, por supuesto completamente "fake".

En el primer "then" comprobamos la respuesta del servicio web. Las solicitudes GET para recuperar datos suelen devolver el código 200 cuando todo ha ido bien. Si es así, entonces obtenemos el texto de la respuesta. En caso contrario escalamos un error, que se tratará más adelante en el catch. Este es un buen truco para dejar un único tratamiento de errores para todas las situaciones que se puedan producir.

Otro de los detalles importantes que tendremos que resolver es la conversión del texto de la respuesta, que normalmente será un JSON, para parsearlo y convertirlo en un array con JSON.parse. Una vez tienes el objeto de usuarios harás lo que necesite tu aplicación, ahí ya de pendende de ti.

Conclusión

En este tutorial hemos aprendido a usar fetch, la manera más moderna con la que realizar conexiones asíncronas (Ajax) en el navegador. Es muy interesante porque nos permite un tratamiento estándar de las conexiones Ajax, ya que funciona igual en todos los navegadores. Además, al implementarse por medio de promesas, podemos generar código muy comprensible y de más fácil mantenimiento que con los tradicionales callbacks.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual