La Fetch API ha rivoluzionato il modo in cui interagiamo con le risorse di rete, mandando definitivamente in pensione il vecchio oggetto XMLHttpRequest (XHR). Integrata nativamente nei browser moderni e in Node.js (dalla versione 18+), questa API basata sulle Promises offre una sintassi pulita, potente e facilmente leggibile per gestire il flusso di dati asincrono.

Effettuare una Richiesta GET di base

Il metodo GET è il più comune per recuperare dati da un'endpoint. Con Fetch, l'operazione è immediata. Tuttavia, è fondamentale implementare un controllo sullo stato della risposta per evitare bug silenti.

Esempio Richiesta GET
// Recupero dati semplice
const response = await fetch('https://api.example.com/users');
const users = await response.json();
console.log(users);

// Implementazione con gestione errori professionale
async function fetchUsers() {
  const response = await fetch('https://api.example.com/users');

  // Verifica se la risposta è andata a buon fine (status 200-299)
  if (!response.ok) {
    throw new Error(`Errore HTTP: ${response.status}`);
  }

  return response.json();
}

Nota bene: A differenza di altre librerie come Axios, la Fetch API non rigetta la Promise in caso di errori HTTP (come 404 o 500). La Promise viene rifiutata solo se si verifica un errore di rete o se il server non è raggiungibile.

Inviare Dati: POST, PUT e DELETE

Per creare o aggiornare risorse sul server, dobbiamo configurare l'oggetto delle opzioni, specificando il metodo, gli header e il corpo della richiesta (body).

POST — Creare una nuova risorsa
const response = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer IL_TUO_TOKEN',
  },
  body: JSON.stringify({
    nome: 'Mario Rossi',
    email: '[email protected]',
  }),
});

const nuovoUtente = await response.json();
PUT — Aggiornamento Completo
await fetch('https://api.example.com/users/42', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ nome: 'Mario Rossi Aggiornato' }),
});
DELETE — Eliminazione
await fetch('https://api.example.com/users/42', {
  method: 'DELETE',
  headers: { 'Authorization': 'Bearer IL_TUO_TOKEN' },
});

Gestione dei Diversi Tipi di Risposta

Non tutte le API restituiscono JSON. La Fetch API mette a disposizione diversi metodi per interpretare il corpo della risposta in base alle necessità del tuo progetto.

Parsing della Risposta
const response = await fetch(url);

// Parsing come oggetto JSON
const data = await response.json();

// Parsing come testo semplice
const testo = await response.text();

// Dati binari (utili per immagini o file)
const blob = await response.blob();

// ArrayBuffer (dati binari grezzi)
const buffer = await response.arrayBuffer();

// Accesso ai metadati
console.log(response.status);     // es: 200
console.log(response.ok);         // true se status tra 200-299
console.log(response.headers.get('Content-Type'));

Utilizzo di AbortController per il Timeout

Spesso è necessario annullare una richiesta se impiega troppo tempo o se l'utente cambia pagina. Ecco come gestire il timeout in modo efficace.

Annullare una richiesta Fetch
const controller = new AbortController();
const signal = controller.signal;

// Impostiamo un timeout di 6 secondi
const timeoutId = setTimeout(() => controller.abort(), 6000);

try {
  const res = await fetch('https://api.example.com/data', { signal });
  clearTimeout(timeoutId);
  const data = await res.json();
} catch (err) {
  if (err.name === 'AbortError') {
    console.warn('Richiesta annullata per timeout');
  } else {
    console.error('Errore imprevisto:', err);
  }
}

Caricamento File con FormData

Per inviare file (come immagini o documenti), non bisogna convertire i dati in JSON. Si utilizza l'oggetto FormData, e il browser gestirà automaticamente i boundary del multipart/form-data.

Upload con FormData
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('userId', '12345');

// NOTA: Non impostare manualmente il Content-Type!
const response = await fetch('/api/upload', {
  method: 'POST',
  body: form,
});

Creazione di un Client API Riutilizzabile

Per evitare di ripetere sempre lo stesso codice, è buona norma creare una classe wrapper che centralizzi la logica delle chiamate.

Esempio di Wrapper API
class ApiService {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  async call(endpoint, options = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });

    if (!response.ok) throw new Error('Errore API');
    return response.json();
  }

  get(path) { return this.call(path); }
  post(path, body) { 
    return this.call(path, { method: 'POST', body: JSON.stringify(body) }); 
  }
}

const api = new ApiService('https://api.test.com');
const data = await api.get('/v1/products');

Errori Comuni e Best Practices

  • Dimenticare response.ok: Ricorda che fetch non "fallisce" se il server risponde con un errore 404 o 500.
  • Parsing multiplo: Il body di una risposta può essere letto una sola volta (es. non puoi chiamare .json() e poi .text()).
  • Gestione degli Header CORS: Assicurati che il server accetti le richieste cross-origin se chiami API su domini diversi.
  • Stringify del Body: Ricorda sempre di usare JSON.stringify() quando invii oggetti JSON nel body.

Ottimizza il tuo Flusso di Lavoro

Utilizza i nostri strumenti gratuiti per formattare i tuoi dati API e codificare i parametri URL in un click.