Fetch, un client HTTP basé sur les promesses
L'API fetch est intégrée nativement aux navigateurs et aux versions récentes de Node. On lui passe une URL, et elle renvoie une Promise qui se résout en un objet Response. Voilà, dans les grandes lignes, toute l'API :
Deux .then à la suite, parce qu'il y a en fait deux étapes asynchrones : d'abord les en-têtes de la réponse arrivent (c'est ce que résout la première promesse), puis le corps est lu et parsé (response.json() renvoie lui aussi une promesse). Le corps n'est téléchargé qu'au moment où tu le demandes explicitement.
Le même enchaînement, écrit avec async/await, se lit comme du code classique de haut en bas :
Deux await, deux points de suspension. Le même boulot, mais dans un ordre de lecture bien plus clair.
L'objet Response
Ce que tu récupères, ce n'est pas directement le corps de la réponse — c'est un objet Response qui contient des métadonnées et des méthodes pour lire ce corps sous différentes formes :
Tu peux lire le corps de la réponse avec .json(), .text(), .blob(), .arrayBuffer() ou .formData(). Chacune de ces méthodes renvoie une promesse. Attention : le corps ne se lit qu'une seule fois — si tu appelles .json() deux fois sur la même réponse, le second appel va lever une exception.
Le piège classique : les erreurs HTTP ne rejettent pas
C'est le truc qui surprend à peu près tout le monde quand on débute avec fetch. Une réponse 404 ou 500 n'est pas considérée comme un rejet. La promesse se résout normalement, simplement avec response.ok === false. Fetch ne rejette que quand la requête elle-même n'a pas pu aboutir — panne DNS, pas de réseau, blocage CORS.
Du coup, un fetch écrit naïvement va te servir gentiment une page d'erreur, puis planter plus tard au moment du .json() :
La solution consiste à vérifier soi-même response.ok et à lever une exception si le serveur a renvoyé un statut d'erreur :
Prenez l'habitude d'écrire ce bloc if (!response.ok). Il a sa place dans chaque wrapper fetch que vous écrirez.
Envoyer une requête POST avec fetch
Par défaut, fetch envoie une requête GET. Pour tout le reste, il faut passer un deuxième argument : un objet d'options.
Trois points à retenir :
methodvaut"GET"par défaut. Précisez-le explicitement pour POST, PUT, DELETE, PATCH.bodyattend une chaîne de caractères (ou unFormData, unBlob, etc.) — fetch ne sérialise pas les objets à votre place. LeJSON.stringify(...), c'est à vous de le faire.- L'en-tête
Content-Typeindique au serveur comment interpréter le corps de la requête. Si vous l'oubliez, la plupart des serveurs traiteront le corps comme du texte brut.
En-têtes, query strings et autres options
Les en-têtes sont un simple objet (ou une instance de Headers). Quant aux query strings, vous les construisez vous-même, généralement avec URLSearchParams :
URLSearchParams s'occupe de l'encodage à votre place — espaces, esperluettes, unicode — du coup vous n'obtenez pas d'URL cassées quand l'entrée contient des caractères qui doivent être échappés.
D'autres options que vous croiserez dans du vrai code : credentials: "include" pour envoyer les cookies en cross-origin, cache: "no-store" pour contourner le cache HTTP, mode: "cors" (généralement la valeur par défaut) pour contrôler le comportement CORS.
Annuler une requête fetch avec AbortController
Parfois, on veut tout simplement laisser tomber — l'utilisateur a tapé une nouvelle recherche, ou la requête traîne en longueur. AbortController est fait pour ça :
controller.abort() fait échouer la promesse du fetch avec une DOMException dont le name vaut "AbortError". Le bloc finally nettoie le timer : comme ça, une requête qui aboutit ne laisse pas de minuterie traîner dans la nature.
Ce schéma — fetch, timeout et nettoyage — mérite clairement d'être encapsulé dans une fonction utilitaire qu'on réutilise partout.
Un wrapper réutilisable
En assemblant tout ça, on obtient un petit helper qui gère le boilerplate une bonne fois pour toutes :
Un seul endroit pour modifier les en-têtes, un seul pour gérer les erreurs, un seul pour traiter les réponses vides. Toute application un peu sérieuse finit par avoir ce genre de wrapper.
La suite : gérer les erreurs en asynchrone
fetch est l'un des endroits où les erreurs asynchrones font le plus souvent surface, et la vérification de response.ok n'est qu'une pièce du puzzle. La page suivante s'attaque à la gestion des erreurs avec les promesses et async/await — où partent les erreurs, comment les attraper, et les pièges classiques qui les laissent passer sans rien dire.
Questions fréquentes
Comment utiliser fetch en JavaScript ?
Il suffit d'appeler fetch(url) avec l'URL cible. La fonction renvoie une Promise qui se résout avec un objet Response. Pour récupérer le corps en JSON, on appelle response.json() (qui renvoie elle aussi une promesse). Avec async/await, ça donne : const res = await fetch(url); const data = await res.json();.
Comment envoyer une requête POST avec fetch ?
On passe un second argument à fetch avec method: 'POST', un objet headers (en général 'Content-Type': 'application/json') et un body. Attention : fetch ne sérialise pas le corps tout seul, il faut passer vos objets dans JSON.stringify(...) avant de les envoyer.
Pourquoi fetch ne rejette pas sur un 404 ou un 500 ?
Parce que fetch ne considère comme erreur que les problèmes réseau : DNS, absence de connexion, blocage CORS. Pour fetch, un 404 ou un 500 reste une réponse valide — la promesse est résolue. C'est à vous de tester response.ok (qui vaut true pour les codes 200–299) ou response.status, et de lever une exception si le serveur a renvoyé une erreur.
Peut-on annuler une requête fetch ?
Oui, grâce à AbortController. On en crée un, on passe son signal à fetch via l'objet d'options, puis on appelle controller.abort() au moment où on veut couper la requête. La promesse est alors rejetée avec une AbortError que vous pouvez intercepter dans votre catch.