Fetch API

Bentornato.
Nella lezione precedente hai imparato local storage.
Local storage permette a JavaScript di ricordare piccoli pezzi di dati nel browser.
Molto utile.
Molto pratico.
Molto “il browser ora ha un piccolo quaderno.”
Oggi insegniamo a JavaScript come ottenere dati da fuori dalla pagina.
Qui le cose diventano molto reali.
I siti web raramente tengono tutti i dati dentro un solo file JavaScript.
Spesso caricano dati da:
- API;
- server;
- file JSON;
- database tramite endpoint backend;
- altri servizi.
Per ottenere quei dati, JavaScript usa la Fetch API.
Fetch permette a JavaScript di chiedere dati.
Il browser dice:
Vado a prenderli.
JavaScript risponde:
Bene. Per favore non tornare con il caos.
A volte torna con dati.
A volte torna con un errore.
A volte torna con qualcosa che ti fa mettere in dubbio le tue scelte di carriera.
Benvenuto nello sviluppo web.
Cosa Imparerai
In questa lezione imparerai:
- che cos’è la Fetch API;
- che cos’è JSON;
- perché
fetch()è asincrono; - come caricare un file JSON locale;
- come usare
asynceawait; - come convertire una response in JSON;
- come mostrare messaggi di loading;
- come gestire errori con
tryecatch; - come mostrare dati caricati nel DOM;
- come costruire una piccola lista prodotti.
Alla fine di questa lezione, la tua pagina caricherà dati da un file JSON e li mostrerà sullo schermo.
Questo è un grande passo.
Finora la maggior parte dei dati viveva direttamente dentro JavaScript.
Ora JavaScript inizierà a prendere dati da fuori.
Come un messaggero frontend.
Con scarpe migliori.
Che Cos'è Fetch?
fetch() è una funzione JavaScript usata per richiedere dati.
Esempio:
fetch("products.json");
Questo chiede al browser di caricare un file chiamato products.json.
Ma c’è una cosa importante.
fetch() non restituisce i dati immediatamente.
Serve tempo.
Anche se il file è piccolo.
Anche se il file è locale.
Anche se chiedi molto gentilmente.
Quindi JavaScript tratta fetch() come asincrono.
Questo significa:
Inizia la richiesta ora.
Continua quando il risultato è pronto.
Questo è importante.
Molto importante.
Internet non è istantaneo.
Anche quando finge di esserlo.
Che Cos'è JSON?
JSON significa JavaScript Object Notation.
È un formato testuale usato per salvare e inviare dati.
Assomiglia agli oggetti JavaScript.
Esempio JSON:
{
"name": "JavaScript Course",
"price": 49,
"available": true
}
JSON è ovunque.
Le API usano JSON.
I backend restituiscono JSON.
Le app frontend leggono JSON.
Il tuo futuro backend Java Spring Boot probabilmente manderà JSON.
Il tuo frontend probabilmente lo berrà come caffè.
Con attenzione.
Perché JSON sbagliato crea tristezza.
Crea il Progetto
Crea una cartella per questa lezione:
mkdir javascript-lesson11
cd javascript-lesson11
touch index.html
touch script.js
touch products.json
Il progetto dovrebbe essere così:
javascript-lesson11/
index.html
script.js
products.json
Importante:
Per questa lezione, non aprire index.html direttamente con doppio click.
Perché fetch() potrebbe non caricare correttamente file locali da file://.
Usa un server locale.
Per esempio, con Caddy:
caddy file-server --listen :8080
Poi apri:
http://localhost:8080
Ora il browser può caricare correttamente il file JSON.
Niente drago framework.
Solo un piccolo server locale.
Civile.
Scrivi il File JSON
Apri products.json e aggiungi:
[
{
"id": 1,
"name": "JavaScript Course",
"price": 49,
"available": true
},
{
"id": 2,
"name": "HTML Course",
"price": 29,
"available": true
},
{
"id": 3,
"name": "CSS Course",
"price": 39,
"available": false
}
]
Questo è un array di oggetti.
Ogni oggetto rappresenta un prodotto.
Ogni prodotto ha:
id;name;price;available.
Questo è molto comune.
Lista di prodotti?
Array di oggetti.
Lista di utenti?
Array di oggetti.
Lista di post del blog?
Array di oggetti.
JavaScript vede array di oggetti ovunque.
Come piccioni in una piazza.
Scrivi l'HTML
Apri index.html e aggiungi:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch API</title>
</head>
<body>
<h1>Fetch API</h1>
<button id="loadButton">Carica Prodotti</button>
<p id="message">Clicca il pulsante per caricare i prodotti.</p>
<ul id="productList"></ul>
<script src="script.js"></script>
</body>
</html>
Abbiamo:
- un pulsante;
- un’area messaggio;
- una lista per i prodotti.
Semplice.
Pulito.
Pronto a ricevere dati.
La pagina aspetta.
Come un cameriere con un vassoio vuoto.
Il Tuo Primo Fetch
Apri script.js e aggiungi:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
console.log(products);
}
loadButton.addEventListener("click", loadProducts);
Avvia il server locale:
caddy file-server --listen :8080
Apri:
http://localhost:8080
Clicca il pulsante.
Apri la console.
Dovresti vedere l’array di prodotti.
Complimenti.
JavaScript ha caricato dati da un file JSON.
Questo è reale.
Piccolo reale.
Ma reale.
Capire async e await
Guarda questa funzione:
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
console.log(products);
}
La parola async significa:
Questa funzione fa lavoro asincrono.
La parola await significa:
Aspetta che questa operazione finisca prima di continuare.
Questa riga:
const response = await fetch("products.json");
aspetta che il file venga caricato.
Questa riga:
const products = await response.json();
aspetta che la response venga convertita in dati JavaScript.
Senza await, JavaScript non aspetta.
E poi il codice si confonde.
Come provare a mangiare pasta prima che sia cotta.
Tecnicamente possibile.
Emotivamente sbagliato.
Che Cos'è response?
fetch() ci dà un oggetto response.
Esempio:
const response = await fetch("products.json");
La response contiene informazioni sulla richiesta.
Non è ancora il dato finale.
Per ottenere dati JSON, usiamo:
const products = await response.json();
Questo converte il corpo della response in dati JavaScript.
Importante:
Anche response.json() è asincrono.
Per questo usiamo await.
JavaScript ha bisogno di tempo per leggere e interpretare JSON.
Anche JavaScript ha bisogno di un momento.
Rispetta il processo.
Mostrare i Prodotti nella Pagina
Ora mostriamo i prodotti nel DOM.
Aggiorna script.js:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
productListElement.innerHTML = "";
for (const product of products) {
const listItem = document.createElement("li");
listItem.textContent = `${product.name} - €${product.price}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `${products.length} prodotti caricati.`;
}
loadButton.addEventListener("click", loadProducts);
Aggiorna il browser.
Clicca il pulsante.
Ora i prodotti appaiono nella pagina.
Cosa è successo?
JavaScript:
- ha caricato
products.json; - lo ha convertito in dati JavaScript;
- ha fatto un loop sui prodotti;
- ha creato elementi
<li>; - li ha aggiunti alla pagina.
Questo è frontend development.
I dati arrivano.
Il DOM si aggiorna.
L’utente vede contenuto.
Bellissimo.
Leggermente drammatico.
Ma bellissimo.
Aggiungere lo Stato di Disponibilità
Ora mostriamo se un prodotto è disponibile.
Aggiorna questa riga:
listItem.textContent = `${product.name} - €${product.price}`;
con questa:
const status = product.available ? "Disponibile" : "Non disponibile";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
Loop completo:
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
Questo usa un operatore ternario.
Significa:
Se product.available è true, usa "Disponibile".
Altrimenti usa "Non disponibile".
Breve.
Utile.
Un po’ sospetto all’inizio.
Ma amichevole con la pratica.
Aggiungere uno Stato di Loading
Caricare dati richiede tempo.
Quindi dovremmo mostrare un messaggio di loading.
Aggiorna loadProducts:
async function loadProducts() {
messageElement.textContent = "Caricamento prodotti...";
productListElement.innerHTML = "";
const response = await fetch("products.json");
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `${products.length} prodotti caricati.`;
}
Ora quando l’utente clicca, la pagina dice:
Caricamento prodotti...
Questa è una buona esperienza utente.
Agli utenti piace sapere che qualcosa sta succedendo.
Altrimenti cliccano di nuovo.
E di nuovo.
E di nuovo.
Poi la tua app riceve 47 richieste e inizia a piangere.
Gestire Errori con try e catch
A volte fetch fallisce.
Forse il nome del file è sbagliato.
Forse il server non è avviato.
Forse internet sta avendo una crisi filosofica.
Dobbiamo gestire gli errori.
Aggiorna script.js:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
messageElement.textContent = "Caricamento prodotti...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `${products.length} prodotti caricati.`;
} catch (error) {
messageElement.textContent = "Impossibile caricare i prodotti.";
console.log(error);
}
}
loadButton.addEventListener("click", loadProducts);
Ora gli errori non distruggono l’atmosfera in silenzio.
Se qualcosa va storto, l’utente vede un messaggio.
E lo sviluppatore vede l’errore in console.
Tutti ricevono informazioni.
Molto sano.
Molto raro.
Controllare response.ok
C’è un altro dettaglio importante.
fetch() non lancia sempre un errore per risposte HTTP sbagliate.
Per esempio, se il file manca, il server può restituire 404.
Quindi dovremmo controllare:
if (!response.ok) {
throw new Error("Impossibile caricare i prodotti.");
}
Aggiorna la parte del fetch:
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Impossibile caricare i prodotti.");
}
const products = await response.json();
Funzione completa:
async function loadProducts() {
messageElement.textContent = "Caricamento prodotti...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Impossibile caricare i prodotti.");
}
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `${products.length} prodotti caricati.`;
} catch (error) {
messageElement.textContent = "Impossibile caricare i prodotti.";
console.log(error);
}
}
Ora il codice è più forte.
Non invincibile.
Ma più forte.
Come il caffè dopo la seconda tazzina.
Aggiungere Stili Migliori
Rendiamo la pagina più bella.
Aggiorna index.html:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch API</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 60px auto;
padding: 0 24px;
background-color: #f3f4f6;
color: #111827;
}
.card {
background-color: white;
padding: 24px;
border: 2px solid #e5e7eb;
border-radius: 18px;
}
h1 {
font-size: 42px;
}
button {
background-color: #2563eb;
color: white;
border: none;
padding: 14px 20px;
border-radius: 999px;
font-weight: 700;
cursor: pointer;
}
button:hover {
background-color: #1d4ed8;
}
.message {
margin-top: 20px;
font-size: 18px;
font-weight: 700;
}
.products {
list-style: none;
padding: 0;
margin-top: 20px;
display: grid;
gap: 12px;
}
.product {
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 14px;
background-color: #f9fafb;
}
.product strong {
display: block;
font-size: 22px;
margin-bottom: 6px;
}
.available {
color: #166534;
font-weight: 700;
}
.unavailable {
color: #991b1b;
font-weight: 700;
}
</style>
</head>
<body>
<h1>Fetch API</h1>
<div class="card">
<button id="loadButton">Carica Prodotti</button>
<p id="message" class="message">Clicca il pulsante per caricare i prodotti.</p>
<ul id="productList" class="products"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
Ora aggiorna la visualizzazione dei prodotti in script.js:
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
const statusClass = product.available ? "available" : "unavailable";
listItem.className = "product";
listItem.innerHTML = `
<strong>${product.name}</strong>
<span>Prezzo: €${product.price}</span><br>
<span class="${statusClass}">${status}</span>
`;
productListElement.appendChild(listItem);
}
Ora i prodotti sembrano card.
Molto meglio.
Meno “HTML grezzo da una grotta.”
Più “piccola app frontend da principiante.”
Progresso.
Codice JavaScript Completo
Ecco il script.js completo:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
messageElement.textContent = "Caricamento prodotti...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Impossibile caricare i prodotti.");
}
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Disponibile" : "Non disponibile";
const statusClass = product.available ? "available" : "unavailable";
listItem.className = "product";
listItem.innerHTML = `
<strong>${product.name}</strong>
<span>Prezzo: €${product.price}</span><br>
<span class="${statusClass}">${status}</span>
`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `${products.length} prodotti caricati.`;
} catch (error) {
messageElement.textContent = "Impossibile caricare i prodotti.";
console.log(error);
}
}
loadButton.addEventListener("click", loadProducts);
Ora hai:
- un file JSON;
- una pagina;
- una richiesta fetch;
- stato loading;
- gestione errori;
- rendering nel DOM.
Questo è un progetto beginner serio.
Piccolo.
Ma serio.
Come un espresso ristretto.
Errori Comuni
Aprire index.html Direttamente
Sbagliato:
file:///home/user/javascript-lesson11/index.html
Meglio:
caddy file-server --listen :8080
Poi apri:
http://localhost:8080
Fetch spesso ha bisogno di un server.
Anche uno locale piccolo.
Non litigare con il browser.
Ha regole.
Molte regole.
Dimenticare await
Sbagliato:
const response = fetch("products.json");
const products = response.json();
Corretto:
const response = await fetch("products.json");
const products = await response.json();
Senza await, non hai ancora i dati.
Hai una promise.
Una promise non è il risultato.
È un risultato futuro.
Come ordinare una pizza.
Lo scontrino non è la pizza.
Ancora pizza.
Ma funziona.
Dimenticare response.json()
Sbagliato:
const products = await response;
Corretto:
const products = await response.json();
La response non è il dato finale.
Devi convertirla in JSON.
JavaScript è potente.
Ma ha comunque bisogno di istruzioni.
Percorso del File Sbagliato
Se il file si chiama:
products.json
allora fetch:
fetch("products.json")
Se il file è in una cartella:
data/products.json
allora fetch:
fetch("data/products.json")
I percorsi devono combaciare.
JavaScript non cercherà nelle tue cartelle come un detective.
Fallirà e basta.
In silenzio.
Come un gatto che butta qualcosa dal tavolo.
Pratica
Crea un nuovo file JSON chiamato students.json.
Aggiungi questo:
[
{
"name": "Anna",
"level": "Beginner"
},
{
"name": "Marco",
"level": "Intermediate"
},
{
"name": "Viktor",
"level": "Beginner"
}
]
Crea un pulsante che carica gli studenti.
Mostra ogni studente nella pagina.
Output esempio:
Anna - Beginner
Marco - Intermediate
Viktor - Beginner
Bonus:
Mostra quanti studenti sono stati caricati.
Molto simile ai prodotti.
Dati diversi.
Stesso schema.
Così funziona la programmazione.
Impara uno schema.
Usalo ovunque.
Fingi che fosse difficile.
Molto professionale.
Mini Challenge
Costruisci un piccolo catalogo corsi.
Crea courses.json con:
- titolo del corso;
- categoria;
- prezzo;
- stato disponibile.
Poi usa fetch() per caricare i corsi e mostrarli come card.
Ogni card deve mostrare:
- titolo;
- categoria;
- prezzo;
- disponibilità.
Bonus:
Mostra solo i corsi disponibili.
Questo significa che puoi usare:
if (course.available) {
// show course
}
Questa sfida combina:
- array;
- oggetti;
- DOM;
- condizioni;
- fetch;
- JSON.
In pratica JavaScript sta diventando una piccola fabbrica di web app.
Complimenti.
E anche: attenzione.
Le fabbriche hanno bisogno di organizzazione.
Riepilogo
Oggi hai imparato:
fetch()carica dati da file o API;- fetch è asincrono;
asyncpermette a una funzione di usareawait;awaitaspetta risultati asincroni;- JSON è un formato dati comune;
response.json()converte una response in dati JavaScript;- messaggi di loading migliorano l’esperienza utente;
tryecatchgestiscono errori;response.okaiuta a rilevare richieste fallite;- i dati caricati possono essere mostrati nel DOM;
- i server locali aiutano a evitare problemi con file locali.
Questo è un grande passo.
Il tuo JavaScript ora può parlare con dati esterni.
Non solo variabili.
Non solo local storage.
File reali.
API dopo.
Server dopo.
Il mondo esterno.
JavaScript ha aperto una finestra.
Speriamo non quella sbagliata.
Prossima Lezione
Nella prossima lezione costruiremo un piccolo progetto finale.
Combineremo:
- variabili;
- array;
- oggetti;
- funzioni;
- DOM;
- eventi;
- form;
- validazione;
- local storage;
- fetch.
Un vero progetto JavaScript da principiante.
Non enorme.
Non spaventoso.
Ma completo.
Il boss finale si avvicina.
Porta caffè.