D3 - Modularité (API, bibliothèques et modules)
Pour aller plus loin…
Utiliser un service via une API, avec Javascript
Considérons le service proposé par la NASA de consultation des photos prises par les missions sur Mars.
Dans la barre d’URL d’un navigateur, saisir :
https://api.nasa.gov/mars-photos/api/v1/manifests/curiosity?api_key=DEMO_KEY
Attention ! Remplacer DEMO_KEY par une clé (jeton) valide.
Lorsque l’on valide, le navigateur envoie une requête HTTP à l’API située au niveau d’un serveur Web.
Ce dernier envoie une réponse HTTP au client qui contient des données formatées. Celles-ci s’affichent dans la fenêtre du navigateur. En voici un extrait :
{"photo_manifest":{"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active","max_sol":3729,"max_date":"2023-02-01","total_photos":627873,"photos":[{"sol":0,"earth_date":"2012-08-06","total_photos":3702,"cameras":["CHEMCAM","FHAZ","MARDI","RHAZ"]}, ..., {"sol":3729,"earth_date":"2023-02-01","total_photos":39,"cameras":["CHEMCAM","NAVCAM"]}]}}
Ces informations correspondent au manifeste des photos prises par une mission, ici de la mission ‘curiosity’.
Il s’agit maintenant de voir comment envoyer la même requête http à partir d’un script écrit en javascript, de récupérer la réponse http, puis d’en exploiter le contenu.
Pour atteindre cet objectif il faut envisager l’utilisation d’une classe appelée : XMLHttpRequest
Etape 1 – Instanciation de la classe (appel du constructeur)
var req_http = new XMLHttpRequest();
Etape 2 – Initialisation de la requête (appel de la méthode open())
// apiMET : STR, méthode utilisée pour la soumission de la requête, valeur : GET ou POST // apiURL : STR, url de l'API + ? + paramètres (clé=valeur&...) req_http.open(apiMET, apiURL, true);
Etape 3 – Envoi de la requête (appel de la méthode send())
req_http.send();
Etape 4 – Attente d’un changement d’état (écoute de l’événement onreadystatechange)
Dès que la valeur de l’attribut readyState change, on exécute le bloc d’instructions contenu dans une fonction.
req_http.onreadystatechange = function(){ // bloc d'instructions }
Etape 5 – Tests des valeurs des attributs ‘readyState’ et ‘status‘, et le cas échéant lecture puis affichage du contenu du corps de la réponse.
Le mot ‘this’ est l’équivalent du mot ‘self’ utilisé en Python.
Les caractères « && » correspond à l’opérateur booléen « AND ».
if(this.readyState == 4 && this.status == 200){ ... }
Le contenu du corps de la réponse a été affecté à l’attribut ‘responseText‘
// Tests des valeurs des attributs 'readyState' et 'status' // le mot 'this' est l'équivalent du mot 'self' utilisé en Python. if(this.readyState == 4 && this.status == 200){ // Le contenu du corps de la réponse a été affecté à l'attribut 'responseText' // Affichage du contenu du corps de la réponse dans un élément HTML document.getElementById("manifeste").innerHTML = req_http.responseText; }
Ouvrir un EDI (Environnement de développement Intégré) comme Geany.
Copier le code contenu dans le bloc qui suit, le coller dans l’EDI, et enfin sauvegarder sous la forme d’un fichier avec extension ‘.html’
Ouvrir un navigateur : activer les outils de développement (Ctrl + Maj + I) et ouvrir l’onglet « Réseau ».
Rechercher dans l’arborescence le fichier html sauvegardé : ouvrir le menu contextuel, sélectionner ‘Ouvrir avec… » et choisir le navigateur qui vient d’être ouvert.
<!DOCTYPE html> <html lang="fr"> <!-- Lycée - Terminale - Spécialité NSI D - Programmation API Nasa API : https://api.nasa.gov/ Mars Rover Photos --> <head> <meta charset="utf-8" /> <title>API - Nasa - Mars Rover Photos</title> </head> <body> <p>Manifeste de la mission</p> <p id="manifeste"></p> </body> <script> // ----------------------------------------------------------------------- // Construction d'une chaîne de caractères correspondant à la requête http // ----------------------------------------------------------------------- var apiMet = "GET"; // Méthode de soumission de la requête var apiKey = "RBRY9REFVaQ3EBwH7zyq3dx4lSVOFVhazhNunAzi"; // Saisir une clé valide var apiUrl = "https://api.nasa.gov/mars-photos/api/v1/manifests/"; var apiMis = "curiosity"; var apiReq = apiUrl + apiMis + "?api_key=" + apiKey; // ----------------------------------------------------------------------- // Utilisation de la classe XMLHttpRequest // ----------------------------------------------------------------------- // Instanciation var req_http = new XMLHttpRequest(); console.log(req_http.readyState); // Initialisation de la requête HTTP req_http.open(apiMet, apiReq, true); console.log(req_http.readyState); // Soumission de la requête HTTP req_http.send(); console.log(req_http.readyState); // Attente du changement de valeur de l'attribut readyState req_http.onreadystatechange = function(){ console.log(req_http.readyState); // Tests des valeurs des attributs 'readyState' et 'status' // le mot 'this' est l'équivalent du mot 'self' utilisé en Python. if(this.readyState == 4 && this.status == 200){ // Affichage du contenu du coprs de la réponse dans un élément HTML document.getElementById("manifeste").innerHTML =req_http.responseText; } } </script> </html>
Lorsqu’on ouvre cette page dans un client web (= navigateur), on voit s’afficher un très long texte, dont voici un aperçu.
{"photo_manifest":{"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active","max_sol":3725,"max_date":"2023-01-28","total_photos":626833,"photos":[{"sol":0,"earth_date":"2012-08-06","total_photos":3702,"cameras":["CHEMCAM","FHAZ","MARDI","RHAZ"]},{"sol":1,"earth_date":"2012-08-07","total_photos":16,"cameras":["MAHLI","MAST","NAVCAM"]},{"sol":2,"earth_date":"2012-08-08","total_photos":74,"cameras":["NAVCAM"]},{"sol":3,"earth_date":"2012-08-09","total_photos":338,"cameras":["MAST"]},{"sol":10,"earth_date":"2012-08-16","total_photos":26,"cameras":["CHEMCAM","MAHLI","NAVCAM"]},{"sol":12,"earth_date":"2012-08-18","total_photos":32,"cameras":["CHEMCAM","NAVCAM"]},{"sol":13,"earth_date":"2012-08-19","total_photos":208,"cameras":["CHEMCAM","MAST","NAVCAM"]},{"sol":14,"earth_date":"2012-08-20","total_photos":70,"cameras":["CHEMCAM","FHAZ","MAST","NAVCAM"]},{"sol":15,"earth_date":"2012-08-21","total_photos":58,"cameras":["CHEMCAM","FHAZ","NAVCAM","RHAZ"]},{"sol":16,"earth_date":"2012-08-22","total_photos":78,"cameras":["FHAZ","NAVCAM","RHAZ"]},{"sol":17,"earth_date":"2012-08-23","total_photos":273,"cameras":["MAST","NAVCAM"]},{"sol":19,"earth_date":"2012-08-25","total_photos":444,"cameras":["CHEMCAM","MAST"]},{"sol":20,"earth_date":"2012-08-26","total_photos":1046,"cameras":["MAST"]},{"sol":21,"earth_date":"2012-08-27","total_photos":73,"cameras":["FHAZ","MARDI","MAST","NAVCAM","RHAZ"]},{"sol":22,"earth_date":"2012-08-28","total_photos":52,"cameras":["CHEMCAM","FHAZ","NAVCAM","RHAZ"]},{"sol":23,"earth_date":"2012-08-29","total_photos":379,"cameras":["MARDI","MAST","NAVCAM"]},
Il est possible de convertir cette chaîne de caractères en objet avec la méthode JSON.parse() de javascript.
On remplace donc la ligne 36 du code précédente par celle-ci :
manMis = JSON.parse(xhttp.responseText);
Dès lors l’objet manMis « s’utilise » comme un dictionnaire en Python, comme en témoigne la capture d’écran suivante de la console Javascript :
Nous pouvons donc modifier le code de la page Web pour afficher les données de cet Objet.
<!DOCTYPE html> <html lang="fr"> <!-- Lycée - Terminale - Spécialité NSI D - Programmation API Nasa API : https://api.nasa.gov/ Mars Rover Photos --> <head> <meta charset="utf-8" /> <title>API - Nasa - Mars Rover Photos</title> </head> <body> <p>Manifeste de la mission</p> <p id="manifeste"></p> <p id="mission"></p> </body> <script> var apiMet = "GET"; var apiKey = "RBRY9REFVaQ3EBwH7zyq3dx4lSVOFVhazhNunAzi"; var apiUrl = "https://api.nasa.gov/mars-photos/api/v1/manifests/"; var apiMis = "curiosity"; var apiReq = apiUrl + apiMis + "?api_key=" + apiKey; var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function(){ if(this.readyState == 4 && this.status == 200){ manMis = JSON.parse(xhttp.responseText); manifeste = ""; manMis = manMis["photo_manifest"]; document.getElementById("mission").innerHTML = manifeste; manifeste += "Nom de la mission : " + manMis["name"] + "<br>"; manifeste += "Date d'amarsissage : " + manMis["landing_date"] + "<br>"; manifeste += "Date de lancement : " + manMis["launch_date"] + "<br>"; manifeste += "Statut : " + manMis["status"] + "<br>"; manifeste += "Date des dernières photos prises - en nombre de jours solaires martiens depuis le jour d'amarsissage (0) : " + manMis["max_sol"] + "<br>"; manifeste += "Date des dernières photos prises - date sur Terre : "+ manMis["max_date"] + "<br>"; nbphotos = manMis["photos"].length; // nombre d'éléments du tableau manMis["photos"] datas = manMis["photos"][nbphotos - 1]; cameras = datas["cameras"]; manifeste += "Liste des caméras ayant pris les derières photos : <br>"; document.getElementById("manifeste").innerHTML = manifeste; } } xhttp.open(apiMet, apiReq, true); xhttp.send(); </script> </html>