Come usare la Fetch API in JavaScript

Fetch è un’API di JavaScript basata sulle promise che ci consente di effettuare richieste Ajax evitando di utilizzare XMLHttpRequest. Come vedremo in questo tutorial, Fetch è molto semplice da usare […]

Avatar di GB Factory
GB Factory 5 Febbraio 2022

Fetch è un'API di JavaScript basata sulle promise che ci consente di effettuare richieste Ajax evitando di utilizzare XMLHttpRequest. Come vedremo in questo tutorial, Fetch è molto semplice da usare e semplifica notevolmente il recupero di dati da un'API. Inoltre, è una funzione supportata ormai in tutti i browser moderni, quindi possiamo usarla senza preoccuparci troppo della sua compatibilità.

Se tuttavia volete assicurare il supporto anche su vecchi browser, come per esempio Internet Explorer 11, potrai usare un polyfill per Fetch come questo, realizzato da GitHub.

Per usare Fetch in Node.js le due opzioni più diffuse sono isomorphic-fetch e node-fetch.

Richieste GET

Iniziamo vedendo come effettuare una semplice richiesta GET andando a prendere dei dati di esempio dall'API di JSONPlaceholder:

fetch('https://jsonplaceholder.typicode.com/users')
  .then(res => res.json())
  .then(res => res.map(user => user.username))
  .then(userNames => console.log(userNames));

In console vedremo come output un array contenente i nomi degli utenti che ci ha restituito l'API:

["Bret", "Antonette", "Samantha", "Karianne", "Kamren", "Leopoldo_Corkery", "Elwyn.Skiles", "Maxime_Nienow", "Delphine", "Moriah.Stanton"]

Dato che necessitiamo di una risposta in JSON, dobbiamo come prima cosa utilizzare il metodo json() per trasformare l'oggetto Response in un oggetto JSON con cui poter interagire. Il metodo text() può essere utilizzato per trasformare la risposta in XML, nel caso volessimo utilizzare quel formato.

Richieste POST, PUT e DELETE

Per effettuare una qualsiasi altra richiesta che non sia GET, dobbiamo passare a fetch un secondo oggetto contenete le opzioni della richiesta, ovvero il metodo da utilizzare (method), le intestazioni utili (headers) e il corpo della richiesta (body):

const nuovoArticolo = {
  title: 'Un articolo molto interessante',
  body: '83',
  userId: 3
}

const opzioni = {
  method: 'POST',
  body: JSON.stringify(nuovoArticolo),
  headers: {
    'Content-Type': 'application/json'
  }
};

fetch('https://jsonplaceholder.typicode.com/posts', opzioni)
  .then(res => res.json())
  .then(res => console.log(res));

Come vedete, il corpo della richiesta (body), deve essere stringato. Puoi approfondire l'utilizzo di questo metodo in questo articolo.

Altri metodi che possono essere utilizzati per la richiesta, oltre a POST, sono DELETE, PUT, HEAD e OPTIONS.

Dall'API di JSONPlaceholder riceveremo una risposta con i dati che abbiamo appena passato con anche un ID associato:

Object {
  body: 83,
  id: 138,
  title: "Un articolo molto interessante",
  userId: 3
}

Gestione degli Errori con Fetch

Quando ci troviamo a gestire eventuali errori generati dalla Fetch API, non possiamo semplicemente aggiungere un catch alla fine della promise, dato che se la richiesta viene conclusa correttamente, non avremo nessun errore.

Per superare questo problema dobbiamo fare affidamento alla proprietà ok dell'oggetto response, che sarà impostata a true o a false in base all'esito della richiesta. Nel caso fosse false potremo usare Promise.reject() per gestire l'errore.

fetch('https://jsonplaceholder.typicode.com/pincopallino', options)
  .then(res => {
    if (res.ok) {
      return res.json();
    } else {
      return Promise.reject({ status: res.status, statusText: res.statusText });
    }
  })
  .then(res => console.log(res))
  .catch(err => console.log('Errore, messaggio:', err.statusText));

In questo esempio la nostra promise sarà rifiutata dato che stiamo cercando di effettuare una richiesta ad un endpoint dell'API che non esiste. Il catch finale verrà eseguito e stamperà in console il seguente messaggio di errore:

"Errore, messaggio: Not Found"

Fetch con Async e Await

Dato che, come abbiamo visto, l'API Fetch è basata sulle promise, possiamo utilizzare delle funzioni async per semplificare ulteriormente il nostro codice.

Ecco un esempio con una funzione asincrona che effettua una richiesta GET, estrae i nomi degli utenti dall'oggetto JSON che è stato restituito e stampa in console il risultato:

async function ottieniUtenti(api) {
  const res = await fetch(api);
  let data = await res.json();

  data = data.map(user => user.username);

  console.log(data);
}

ottieniUtenti('https://jsonplaceholder.typicode.com/users');

In alternativa potremmo restituire una promise dalla nostra funzione asincrona, per poi concatenare un un then dopo aver richiamato la funzione:

async function ottieniUtenti(api) {
  const res = await fetch(api);
  const data = await res.json();

  return data;
}

ottieniUtenti('https://jsonplaceholder.typicode.com/users')
  .then(data => {
    console.log(data.map(user => user.username));
  });

Utilizzando json() viene restituita una promise, quindi, quando nell'esempio restituiamo data, stiamo restituendo una promise.

Infine, possiamo anche aggiungere anche del codice per la gestione di eventuali errori in base al valore di ok, che nel caso fosse false genererà un errore, da gestire poi con un catch nella catena della promise:

async function ottieniUtenti(api) {
  const res = await fetch(api);

  if (!res.ok) {
    throw new Error(res.status); // 404
  }

  const data = await res.json();
  return data;
}

ottieniUtenti('https://jsonplaceholder.typicode.com/pincopallino')
  .then(data => {
    console.log(data.map(user => user.website));
  })
  .catch(err => console.log('Errore, messaggio: ', err.message));

Conclusione

In questa guida abbiamo imparato ad utilizzare la Fetch API di JavaScript effettuando varie tipologie di richieste.