Qu'est-ce qu'une API ?
Une API (Application Programming Interface) est un moyen pour des programmes de communiquer entre eux. Quand votre site a besoin de données (météo, utilisateurs, produits), il les demande à un serveur via une API.
Dans notre métaphore du bâtiment : l'API, c'est le téléphone. Votre bâtiment appelle le fournisseur pour commander des matériaux, et le fournisseur répond avec ce qu'il a en stock.
Une requête API, c'est :
- Vous envoyez une requête (demande) à une URL
- Le serveur traite et envoie une réponse (souvent en JSON)
- Vous utilisez les données dans votre page
fetch() : faire une requête
fetch() est la méthode JavaScript native pour appeler une API :
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log(data.name); // "Leanne Graham"
});
fetch() retourne une Promise : un objet qui représente une opération qui va se terminer plus tard. .then() s'exécute quand la réponse arrive.
.then() / await s'exécute.Au fait, c'est quoi une Promise ?
On en parle depuis le début sans ouvrir le capot. Une Promise est un objet qui représente un résultat pas encore disponible. Elle vit dans l'un de trois états :
- pending (en attente) : l'opération est en cours, on ne sait pas encore.
- fulfilled (réussie) : elle s'est terminée avec une valeur.
- rejected (échouée) : elle a échoué avec une erreur.
Une Promise démarre toujours pending, puis bascule une seule fois vers fulfilled ou rejected. Une fois fixée, elle ne change plus jamais.
resolve l'envoie vers fulfilled (lu par .then), reject vers rejected (lu par .catch).Qui décide du basculement ? Quand on crée une Promise, on lui donne une fonction qui reçoit deux leviers : resolve et reject. On appelle resolve(valeur) quand ça réussit, reject(erreur) quand ça échoue :
const commande = new Promise((resolve, reject) => {
const cafePret = true;
if (cafePret) {
resolve("café chaud"); // → la Promise devient "fulfilled"
} else {
reject("plus de grains"); // → la Promise devient "rejected"
}
});
Et pour récupérer le résultat, deux styles équivalents :
// Style .then / .catch
commande
.then(valeur => console.log("Reçu :", valeur)) // appelé si resolve()
.catch(erreur => console.log("Raté :", erreur)); // appelé si reject()
// Style async / await (try/catch pour l'erreur)
try {
const valeur = await commande; // rend ce que resolve() a passé
} catch (erreur) { // attrape ce que reject() a passé
console.log("Raté :", erreur);
}
C'est exactement ce que fait fetch() en interne : il crée une Promise, appelle resolve quand la réponse du serveur arrive, et reject si le réseau tombe. Toi, tu te contentes de la consommer avec await ou .then().
async/await : la syntaxe moderne
async/await rend le code asynchrone lisible comme du code normal :
async function chargerUtilisateur() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data = await response.json();
console.log(data.name);
}
chargerUtilisateur();
await met le code en pause jusqu'à ce que la Promise soit résolue. async est obligatoire devant la fonction qui utilise await.
Une fonction async renvoie toujours une Promise
Voici le point qui surprend tout le monde : dès que tu mets async devant une fonction, elle renvoie une Promise, quoi que tu fasses à l'intérieur. Même un simple return 42 :
async function f() {
return 42;
}
f(); // Promise {<fulfilled>: 42} ← pas 42 !
const x = await f(); // x = 42 (await déballe la Promise)
En fait, le mot async ne veut pas dire « ça tourne en arrière-plan ». Il veut dire : « cette fonction parle le langage des Promises ». Sa mission, c'est d'emballer automatiquement ta valeur de retour dans une Promise : ton return 42 devient, en coulisses, return Promise.resolve(42).
Et c'est le seul comportement sensé. Une fonction async a le droit de se mettre en pause (à chaque await) et de finir plus tard. Au moment où tu l'appelles, sa valeur finale n'existe peut-être pas encore (le serveur n'a pas répondu...). La seule chose honnête qu'elle peut te rendre tout de suite, c'est un bon de réception : une Promise, qui te livrera la valeur quand elle sera prête.
L'image du comptoir de café : tu commandes, on ne te tend pas le café mais un bipeur (la Promise). Plus tard ça bipe (la Promise est résolue) et tu récupères ton café (la valeur). Une fonction async te tend toujours un bipeur, même si le café était déjà prêt : comme ça tu la traites toujours pareil, sans avoir à deviner si le résultat est prêt maintenant ou plus tard.
async met ta valeur dans une Promise (il l'emballe) ; await fait l'inverse et en ressort la valeur (il la déballe).Les deux mots-clés sont donc les deux faces d'une même pièce : async produit une Promise, await déballe une Promise (et attend qu'elle soit prête). C'est pour ça qu'on écrit await f() pour récupérer le 42, et jamais f() tout seul.
JSON : le format des API
JSON (JavaScript Object Notation) est le format standard des API. C'est très similaire aux objets JavaScript :
// Objet JavaScript → texte JSON
const obj = { nom: "Alice", age: 25 };
const texte = JSON.stringify(obj); // '{"nom":"Alice","age":25}'
// Texte JSON → objet JavaScript
const obj2 = JSON.parse(texte); // { nom: "Alice", age: 25 }
Gestion des erreurs : try/catch
Les requêtes réseau peuvent échouer (pas d'internet, serveur en panne). Utilisez try/catch pour gérer les erreurs :
async function charger() {
try {
const response = await fetch("https://api.exemple.com/data");
if (!response.ok) {
throw new Error("Erreur HTTP : " + response.status);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Problème :", error.message);
}
}
Règle d'or : vérifiez toujours response.ok et entourez fetch de try/catch.
What is an API?
An API (Application Programming Interface) is a way for programs to communicate with each other. When your site needs data (weather, users, products), it requests it from a server via an API.
In our building metaphor: the API is the telephone. Your building calls the supplier to order materials, and the supplier responds with what's in stock.
An API request is:
- You send a request to a URL
- The server processes it and sends a response (usually JSON)
- You use the data in your page
fetch() — making a request
fetch() is the native JavaScript method to call an API:
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log(data.name); // "Leanne Graham"
});
fetch() returns a Promise — an object representing an operation that will complete later. .then() runs when the response arrives.
.then() / await runs.By the way, what is a Promise?
We've been talking about it without opening the hood. A Promise is an object representing a result that's not available yet. It lives in one of three states:
- pending (waiting): the operation is in progress, we don't know yet.
- fulfilled (succeeded): it finished with a value.
- rejected (failed): it failed with an error.
A Promise always starts pending, then switches exactly once to fulfilled or rejected. Once settled, it never changes again.
resolve sends it to fulfilled (read by .then), reject to rejected (read by .catch).Who decides the switch? When you create a Promise, you give it a function that receives two levers: resolve and reject. You call resolve(value) on success, reject(error) on failure:
const order = new Promise((resolve, reject) => {
const coffeeReady = true;
if (coffeeReady) {
resolve("hot coffee"); // → the Promise becomes "fulfilled"
} else {
reject("out of beans"); // → the Promise becomes "rejected"
}
});
And to get the result, two equivalent styles:
// .then / .catch style
order
.then(value => console.log("Got:", value)) // called if resolve()
.catch(error => console.log("Failed:", error)); // called if reject()
// async / await style (try/catch for the error)
try {
const value = await order; // returns what resolve() passed
} catch (error) { // catches what reject() passed
console.log("Failed:", error);
}
That's exactly what fetch() does internally: it creates a Promise, calls resolve when the server response arrives, and reject if the network drops. You just consume it with await or .then().
async/await — the modern syntax
async/await makes asynchronous code read like normal code:
async function loadUser() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data = await response.json();
console.log(data.name);
}
loadUser();
await pauses the code until the Promise resolves. async is required before the function that uses await.
An async function always returns a Promise
Here's the point that surprises everyone: the moment you put async in front of a function, it returns a Promise, whatever you do inside. Even a plain return 42:
async function f() {
return 42;
}
f(); // Promise {<fulfilled>: 42} ← not 42 !
const x = await f(); // x = 42 (await unwraps the Promise)
Actually, the word async doesn't mean "this runs in the background". It means: "this function speaks the language of Promises". Its job is to automatically wrap your return value in a Promise: your return 42 becomes, behind the scenes, return Promise.resolve(42).
And it's the only sensible behavior. An async function is allowed to pause (at each await) and finish later. When you call it, its final value may not exist yet (the server hasn't replied...). The only honest thing it can hand you right away is a receipt: a Promise, which will deliver the value once it's ready.
The coffee counter image: you order, they don't hand you the coffee but a buzzer (the Promise). Later it buzzes (the Promise is resolved) and you get your coffee (the value). An async function always hands you a buzzer, even if the coffee was already ready: that way you treat it the same every time, without guessing whether the result is ready now or later.
async puts your value into a Promise (it wraps it); await does the opposite and takes the value back out (it unwraps it).So the two keywords are two sides of the same coin: async produces a Promise, await unwraps a Promise (and waits for it to be ready). That's why you write await f() to get the 42, never f() on its own.
JSON — the API format
JSON (JavaScript Object Notation) is the standard format for APIs. It's very similar to JavaScript objects:
// JavaScript object → JSON text
const obj = { name: "Alice", age: 25 };
const text = JSON.stringify(obj); // '{"name":"Alice","age":25}'
// JSON text → JavaScript object
const obj2 = JSON.parse(text); // { name: "Alice", age: 25 }
Error handling: try/catch
Network requests can fail (no internet, server down). Use try/catch to handle errors:
async function loadData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error("HTTP error: " + response.status);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Problem:", error.message);
}
}
Golden rule: always check response.ok and wrap fetch in try/catch.
Copiez ce prompt dans Claude ou ChatGPT :
Explique-moi les Promises en JavaScript comme si j'étais au restaurant : la commande, l'attente, le plat servi ou l'erreur. Puis montre un exemple avec fetch et async/await.
Sans relire la réponse de l'IA : reprends la métaphore du restaurant et explique les trois états d'une Promise. Qu'est-ce qui la fait passer de l'un à l'autre ?
pending (la commande est passée, le plat n'arrive pas tout de suite) ; elle bascule une seule fois vers fulfilled via resolve(valeur) (le plat servi, lu par .then ou await) ou vers rejected via reject(erreur) (la commande ratée, lue par .catch ou try/catch). Une fois fixée, elle ne change plus jamais. fetch() fait exactement ça en interne.L'IA a oublié d'appeler .json() sur la réponse. Les données ne sont pas parsées. Ajoutez await response.json().
L'IA te propose cette fonction pour récupérer un utilisateur. Ton rôle de relecteur : l'accepter telle quelle ou la rejeter, et dire pourquoi.
async function getUser(id) {
const response = await fetch("https://api.exemple.com/users/" + id);
const data = await response.json();
return data.name;
}
try/catch (si le réseau tombe, la Promise est rejetée et l'erreur remonte sans être gérée) et surtout aucun contrôle de response.ok. Subtilité importante : fetch() ne rejette pas sur un 404 ou un 500. Un response.json() sur une page d'erreur renverra autre chose que prévu, et data.name sera undefined sans le moindre avertissement. Le réflexe pro : if (!response.ok) throw new Error(...) avant de parser, le tout dans un try/catch.Sans remonter dans la leçon : que renvoie fetch(url) immédiatement, et pourquoi faut-il deux await pour obtenir les données JSON ?
fetch(url) renvoie tout de suite une Promise (en attente), pas les données. Premier await : on attend l'objet Response (les en-têtes, le statut HTTP). Le corps n'est pas encore lu. Deuxième await : response.json() lit le flux du corps et le parse en objet JavaScript, ce qui est lui aussi asynchrone, d'où le second await.fetch() ?JSON.parse() ?try/catch avec fetch ?async devant une fonction ?You can fetch data from an API and display it. But the moment you reload the page, everything vanishes. The next lesson keeps memory inside the browser: LocalStorage, put to work in a real mini-project that ties together everything you've learned.
Lesson 8: LocalStorage and mini-project →