Présentation de l’API JavaScript Fetch
Par rapport à XMLHttpRequest et aux bibliothèques construites autour de celui-ci, comme JQuery.ajax, l’API fetch définit une manière plus moderne et plus propre d’effectuer des requêtes asynchrones, basée sur l’utilisation de promesses. Dans cet article, nous verrons certaines des interfaces fournies par l’API, comme Request et Response, et nous apprendrons à utiliser la méthode fetch pour effectuer divers types de requêtes asynchrones.
Dans ce tutoriel, vous allez apprendre :
- Comment envoyer des requêtes asynchrones à l’aide de la méthode fetch
- Comment utiliser les objets Request et Response fournis par l’API fetch
Configuration logicielle requise et conventions utilisées
Utilisation de base
L’API Fetch représente les requêtes et les réponses HTTP à l’aide des interfaces Request et Response et fournit la méthode fetch pour envoyer les requêtes de manière asynchrone. Commençons par un exemple très basique de la façon de l’utiliser.
La méthode fetch n’a qu’un seul argument obligatoire, qui est soit le chemin d’accès de la ressource à récupérer, soit un objet Request. Lorsque seul ce paramètre est transmis à la fonction, une requête GET est exécutée pour récupérer la ressource spécifiée. Pour les besoins de cet exemple, nous allons utiliser l’appel API NASA qui renvoie des informations sur l’astronomique « image du jour » au format JSON. Voici notre code :
fetch('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
.then(response => response.json())
.then(json_object => console.log(json_object))
.catch(reason => console.log(reason))Expliquons brièvement comment fonctionne le code ci-dessus. La fonction fetch renvoie une promesse : si cette promesse est tenue, elle se résout en un objet Response qui représente la réponse HTTP à la requête que nous avons envoyée.
La méthode then de l’objet promise est appelée lorsque la promesse existe dans l’état en attente. Rappelons que la méthode se retourne une nouvelle promesse et accepte jusqu’à deux callbacks comme arguments : le premier est appelé si la promesse est tenue ; la seconde s’il est rejeté. Ici, nous n’avons fourni que le premier puisque nous avons utilisé la méthode catch à cet effet (nous parlerons des erreurs de gestion dans une minute).
Le callback utilisé comme premier argument de la méthode then prend la valeur d’exécution de la promesse comme argument, qui dans ce cas est l’objet Response. Cet objet, parmi les autres, a une méthode appelée json() que nous appelons dans le corps du callback. À quoi sert cette méthode ? Il lit le flux de réponses jusqu’à sa fin et se renvoie une promesse qui se résout avec le corps de la réponse analysé au format JSON.
Comme nous le savons, si une fonction de gestionnaire de la méthode then renvoie une promesse, la valeur d’exécution de ladite promesse est utilisée comme valeur d’exécution de la promesse renvoyée par la méthode then elle-même. C’est pourquoi l’objet JSON est disponible en argument du premier callback de la deuxième méthode then dans l’exemple. Tout ce qui précède se produit de manière asynchrone. Voici le résultat de l’exécution du code :
{
"copyright": "Emilio Rivero Padilla",
"date": "2019-05-21",
"explanation": "These three bright nebulae are often featured on telescopic
tours of the constellation Sagittarius and the crowded starfields of the central
Milky Way. In fact, 18th century cosmic tourist Charles Messier cataloged two of
them; M8, the large nebula just left of center, and colorful M20 on the top
left. The third emission region includes NGC 6559 and can be found to the right
of M8. All three are stellar nurseries about five thousand light-years or so
distant. Over a hundred light-years across, the expansive M8 is also known as
the Lagoon Nebula. M20's popular moniker is the Trifid. Glowing hydrogen gas
creates the dominant red color of the emission nebulae. In striking contrast,
blue hues in the Trifid are due to dust reflected starlight. Recently formed
bright blue stars are visible nearby. The colorful composite skyscape was
recorded in 2018 in Teide National Park in the Canary Islands, Spain.",
"hdurl": "https://apod.nasa.gov/apod/image/1905/M8M20_Padilla_1534.avif",
"media_type": "image",
"service_version": "v1",
"title": "Deep Field: Nebulae of Sagittarius",
"url": "https://apod.nasa.gov/apod/image/1905/M8M20_Padilla_960.avif"
}Dans l’exemple ci-dessus, nous avons analysé le corps de la réponse au format JSON. Il y a des cas où nous voulons analyser le corps de la réponse différemment. Certaines méthodes qui peuvent nous aider dans ces cas sont les suivantes :
Response.blob(): prend un flux de réponses et le lit jusqu’à ce qu’il se termine. Renvoie une promesse qui se résout en un objetBlob, qui est un objet de type fichier de données brutes immuables.Response.text(): lit un flux de réponses et renvoie une promesse qui se résout en texte, en particulier en objetUSVString.Response.formData(): lit un flux de réponses et renvoie une promesse qui se résout en un objetFormDataqui représente les champs de formulaire et leurs valeurs.Response.arrayBuffer(): lit un flux de réponses et renvoie une promesse qui se résout en un objetArrayBuffer, utilisé pour représenter des données binaires brutes.
Envoi de requêtes plus complexes
Celui que nous avons vu ci-dessus était le cas d’utilisation le plus simple possible de la méthode fetch. Il y a des cas où nous devons définir et envoyer des demandes plus complexes. Nous avons deux façons d’accomplir la tâche : la première consiste à fournir un second paramètre à la méthode fetch, un objet init ; la seconde implique la création explicite d’un objet Request, qui est ensuite passé en argument à la méthode fetch. Voyons les deux.
Fournir les paramètres de demande
Supposons que nous souhaitions effectuer une requête POST, en envoyant des données à un emplacement spécifié. Si nous voulons spécifier les paramètres nécessaires pour accomplir cette tâche directement lors de l’exécution de la méthode fetch, nous pouvons lui passer un deuxième argument, qui est un objet qui nous permet d’appliquer des paramètres personnalisés à la demande. On peut écrire :
fetch('https://httpbin.org/post', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
}) Comme ci-dessus, le premier argument de la méthode fetch représente la destination de la requête. Dans ce cas, nous envoyons notre demande à https://httpbin.org/post, qui est un point de terminaison fourni par le service httbin.org pour tester les requêtes POST.
Le deuxième argument facultatif de la fonction, comme nous l’avons dit ci-dessus, est un objet que nous pouvons utiliser pour spécifier des paramètres supplémentaires pour la requête. Dans ce cas, tout d’abord, nous avons spécifié le verbe HTTP qui doit être utilisé pour la requête (POST). Après cela, nous avons utilisé une autre interface fournie par l’API fetch, Headers, qui comprend des méthodes et des propriétés utiles pour manipuler les requêtes et les en-têtes de réponse. Dans ce cas, nous définissons simplement le paramètre d'en-tête 'Content-Type', en déclarant le type de contenu porté par nos requêtes comme application/json. Enfin, nous avons défini le corps réel de la requête : nous avons utilisé la méthode stringify de l’objet JSON pour convertir un objet en chaîne JSON.
En exécutant le code ci-dessus, une requête POST est envoyée à l’URL que nous avons spécifiée. Le service httpbin.org, dans ce cas, renvoie une réponse qui a elle-même 'application/json' comme type de contenu, et décrit les données que nous avons envoyées avec notre demande :
fetch('https://httpbin.org/post', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
})
.then(response => response.json())
.then(json_object => console.log(json_object))Le résultat est, comme nous l’avons dit plus haut, une description de notre demande :
{
"args": {},
"data": "{\"Name\":\"Frodo\",\"Lastname\":\"Baggins\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.5",
"Content-Length": "37",
"Content-Type": "application/json",
"Dnt": "1",
"Host": "httpbin.org",
"Origin": "http://localhost:8080",
"Referer": "http://localhost:8080/",
"User-Agent": "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:66.0)
Gecko/20100101 Firefox/66.0"
},
"json": {
"Lastname": "Baggins",
"Name": "Frodo"
},
"origin": "xx.xx.xx.xx, xx.xx.xx.xx",
"url": "https://httpbin.org/post"
}Construction manuelle d’un objet Request
Comme alternative au code ci-dessus, nous pouvons créer un objet Request explicitement, puis le passer à la méthode fetch :
let request = new Request('https://httpbin.org/post', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
})Pour l’envoyer à l’aide de fetch, il suffit d’écrire :
fetch(request)
.then(response => response.json())
.then(json_object => console.log(json_object))
Gestion des erreurs
Une différence fondamentale entre le comportement de la méthode fetch et celui de JQuery.ajax() est la façon dont une réponse avec un statut d’erreur HTTP (un code d’état qui n’est pas dans la plage 200-299) est traitée. Dans ce cas, lors de l’utilisation de la méthode fetch, la promesse renvoyée par celle-ci est toujours considérée comme remplie. Le seul cas où la promesse est rejetée est lorsqu’il y a une erreur de communication et que la demande ne peut pas atteindre sa destination.
Clarifions-le avec un exemple. Toujours à l’aide du service httpbin.org, nous envoyons une requête GET au point de terminaison « https://httpbin.org/post » que nous avons utilisé dans l’exemple précédent, qui accepte uniquement les requêtes POST. Tout d’abord, nous voyons ce qui se passe lors de l’utilisation de JQuery.ajax() :
$.ajax({type: 'get', url: 'https://httpbin.org/post'})
.then(() => console.log('The promise was fulfilled!'))
.catch(jqXHR => console.log(`Promise rejected because status code was ${jqXHR.status}`))Le code ci-dessus renvoie :
Promise rejected because status code was 405Cela indique que la promesse a été rejetée et que le rappel de la méthode catch a donc été appelé. Lorsque la même requête est envoyée à l’aide de la méthode fetch, la promesse résultante n’est pas rejetée :
fetch('https://httpbin.org/post')
.then(response => console.log(`Promise has been fulfilled even if response status is ${response.status}`))
.catch(reason => console.log('Promise has been rejected!'))Le résultat de l’exécution du code ci-dessus est le suivant :
Promise has been fulfilled even if response status is 405Que s’est-il passé? Étant donné que nous avons utilisé un verbe HTTP not allowed pour le point de terminaison spécifié, nous avons reçu une réponse avec un code d’état Method Not Allowed (405). Cependant, cela n’a pas provoqué le rejet de la promesse, et le rappel de la méthode then a été appelé. Si nous essayons le même code en changeant uniquement la destination de la requête en un chemin inexistant, 'https://foo.bar', le code retourne :
Promise has been rejected!Cette fois, le callback utilisé comme argument de la méthode catch a été appelé. Il est très important de se souvenir de ce comportement : la promesse renvoyée par la méthode fetch n’est rejetée que si la communication avec le serveur échoue et que la requête ne peut pas être complétée. Pour être absolument sûr que notre requête est réussie, nous devons vérifier le code d’état de l’objet Response, qui est disponible dans sa propriété status, ou tester la propriété ok read-only, qui contient un booléen indiquant si le résultat a réussi ou non.
Conclusions
Dans ce tutoriel, nous avons appris à connaître l’API de récupération Javascript et avons vu comment nous pouvons l’utiliser comme alternative à d’autres méthodes d’exécution de requêtes asynchrones comme JQuery.ajax. Nous avons vu comment effectuer des requêtes de base, et comment construire des requêtes plus complexes. Nous avons également examiné comment la promesse renvoyée par la méthode fetch se comporte lorsqu’une réponse avec un code d’état hors de la plage 200-299 est reçue, et lorsqu’une erreur de connexion se produit. Pour en savoir plus sur l’API fetch, vous pouvez consulter la documentation Web de Mozilla.