Utiliser des APIs Web avec fetch
Objectifs: Ce TP a pour un double objectif :
-
vous familiariser avec les requêtes réseau depuis une application WEB en utilisant l'API fetch de JavaScript
-
au travers de l'utilisation de fetch comprendre la mise en oeuvre de la programmation asynchrone en JavaScript à l'aide des Promesses
Documentations fetch et sur les promesses JavaScript
Dans ce TP vous allez travailler avec l'API OpenWeather. OpenWeather API est une interface de programmation d'application (API) fournie par OpenWeather, une entreprise qui fournit des informations météorologiques mondiales. L'API permet aux développeurs de créer des applications qui utilisent des données météorologiques en temps réel, telles que les prévisions météorologiques actuelles, les prévisions à court terme et à long terme, les données historiques, les alertes météorologiques, les données de qualité de l'air, et bien plus encore.
En utilisant l'API OpenWeather, les développeurs peuvent accéder à des données météorologiques précises et fiables pour n'importe quelle région du monde, ainsi que pour des intervalles de temps spécifiques. Ces données sont fournies dans un format JSON ou XML, ce qui les rend facilement utilisables pour la création d'applications météorologiques pour les ordinateurs de bureau, les smartphones, les tablettes et les autres appareils.
L'API OpenWeather offre également une variété de fonctionnalités, telles que la possibilité de personnaliser les requêtes pour récupérer des données spécifiques, de fournir des données historiques pour une période spécifique, de recevoir des alertes météorologiques en temps réel, et bien plus encore.
1. Obtenir une clé d'API
Pour utiliser l'API OpenWeather, vous devez d'abord vous inscrire sur le site web d'OpenWeather pour obtenir une clé d'API (API key) qui vous permettra d'accéder aux données météorologiques. Une fois que vous aurez votre clé d'API, vous pourrez utiliser l'API en envoyant des requêtes HTTP à l'URL de l'API, qui est https://api.openweathermap.org/data/2.5/weather.
Pour vous inscire rendez-vous à l'URL https://home.openweathermap.org/users/sign_up Le processus d'inscription est très simple.
Une fois votre adresse mail confirmée et votre compte créé vous pouvez accéder à votre clé d'API qui vous sera nécessaire pour effectuer des requêtes auprès de OpenWeatherMap.
Attention : La validation de la clé n'est pas immédiate. Il se peut qu'il vous faille attendre un délai de quelques minutes à quelques heures avant que votre clé ne soit pleinement activée.
1. Tester une API avec l'outil Postman
Postman est un outil de développement web qui permet d'exécuter des appels HTTP directement depuis une interface graphique. Il est utilisé pour interagir avec une API et est un outil de référence dans le monde du développement Web. Avec Postman, vous pouvez facilement effectuer des requêtes HTTP via une interface graphique, choisir l'URL et la méthode HTTP (GET, POST, PUT, PATCH, DELETE ...), définir les en-têtes de requête (headers), fixer les valeurs des éventuels paramètres de requête (query params) et dans certains cas fournir le corps (body) de la requête.
Postman est disponible en plusieurs versions, dont une version gratuite et une version payante. La version gratuite de Postman (Postman Free) est destinée aux développeurs individuels et aux petites équipes. Elle offre des fonctionnalités de base telles que la création de requêtes HTTP, la gestion des environnements, la documentation des API, etc. C'est avec cette version que nous allons expérimenter.
Pour utiliser Postman, il faut tout d'abord vous enregister sur le site de Postman. Ensuite vous pouvez l'utiliser soit depuis un application à installer sur votre ordinateur, soit depuis d'une application web dans votre navigateur. Il existe depuis peu un extension Postman pour VSCode qui permet de développer et tester votre API directement depuis VSCode. C'est cette dernière que nous allons utiliser pour ce TP.
1.1 Installer l'extension Postman pour VSCode
-
Avant tout créez un répertoire AWA et dans celui-ci un répertoire TP02 dans lequel vous rangerez le travail effectué au cours de ce TP,
-
Placez vous dans ce répertoire et lancez VS Code
cd AWA/TP02
code . & -
Installez l'extension Postman comme indiqué sur la figure ci-dessous.
-
Une fois l'extension installée, lancez-la et connectez vous avec Postman. Si vous n'avez pas encore de compte Postman, créez-en un.
1.2 Créer et exécuter une requête
-
Créez une nouvelle collection que vous nommerez OpenWeather API, elle vous permettra de regrouper les requêtes liées à cette API.
-
Dans cette collection créez une nouvelle requête que vous nommerez Current Weather
-
Saisissez l'url suivante https://api.openweathermap.org/data/2.5/weather qui permet d'accédez au service de consultation des condition météorologiques courantes en un lieu donné
-
Dans l'onglet Params saisissez un premier paramètre de nom q et de valeur Grenoble puis un second paramètre de nom appid et de valeur la clé d'API pour OpenWeatherMap que vous avez obtenue précédemment (voir obtenir une clé d'API).
-
Envoyez la requête et observez la réponse reçue
-
Consultez la documentation de cette API afin de comprendre le format des données produites. Pour cela rendez-vous à l'URL https://openweathermap.org/current.
-
Vous avez pu constater que la valeur pour la température est plutôt étrange. Cela vient du fait que par défaut les mesures de températures sont exprimés en ° Kelvin. Consultez la documentation de l'API pour trouver comment obtenir des températures en ° Celsius et modifiez votre requête en conséquence afin de régler ce problème.
Correction
il suffit d'ajouter le paramètre units avec la valeur metric à l'URL de la requête
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=Paris&appid=${apiKey}&units=metric`;
-
Faites de même pour que la description des conditions météorologiques ne soit plus en anglais mais en français.
-
Une fois votre requête mise au point, pensez à la sauvegarder.
2. Appeler l'API Current Weather Data depuis JavaScript
Maintenant que vous avez compris le fonctionnement et le paramétrage de la requête pour obtenir la météo courrante, vous allez effectuer cette requête depuis du code JavaScript, dans un premier temps avec node.js
-
Postman permet de générer du code afin d'effecuer la requête depuis différents outils et différents langages de programmation. Générez le code pour JavaScript.
-
Créez un fichier javascript testOpenWeather.js et copiez dans celui-ci le code (Code snippet) généré par Postman. Exécutez testOpenWeather.js depuis un terminal et vérifiez qu'il fonctionne correctement.
-
Le programme précédent récupère la réponse au format texte et affiche le texte brut de celle-ci. Modifiez le programme afin de lire la réponse au format JSON et d'afficher la description des conditions météo, la température courante et la date et l'heure comme sur la figure ci-dessous :
3. Afficher dans une page web la météo d'un lieu
Dans un premier temps vous allez faire une page HTML très simple qui lorsqu'elle est chargée affiche la météo d'un lieu fixé en dur dans le code de la page.
-
Créez un fichier HTML weather1.html et ajoutez le code suivant dans l'élément body :
-
Créez un fichier JavaScript nommé weather1.js dans lequel vous recopierez le code de testOpenWeather.js réalisé à l'exercice 2.
-
Modifiez le code JavaScript afin de ne plus afficher les données sur la console mais dans les éléments prévus à cet effet dans la page HTML.
-
Enregistrez les deux fichiers et ouvrez le fichier HTML dans votre navigateur. Vérifiez que les données météorologiques pour Paris s'affichent correctement sur la page.
-
Dans le code JavaScript on utilise le nom de la ville pour spécifier le lieu à considérer dans la requête. Vous avez peut être remarqué que cet usage du nom du lieu est déprécié (deprecated) et qu'il est conseillé d'utiliser plutôt des coordonnées géographiques (latitude et longitude). Modifiez votre requête pour remplacer le paramètre q=Paris par les données de latitude et longitude de cette ville (latitude : 48° 51′ 24″ nord, longitude 2° 21′ 07″ est).
<body>
<h1>Météo de Paris</h1>
<ul>
<li>
<p>Date : <span id="date"></span></p>
</li>
<li>
<p>Description : <span id="description"></span></p>
</li>
<li>
<p>
Température : <span id="température"></span>
</p>
</li>
</ul>
<script src="weather1.js"></script>
</body>
Correction
il suffit de remplacer le paramètre q par les deux paramètres lat et lon. Par contre il faut transformer les coordonnées géographiques de DMS (Degrés Minutes Secondes) en DD (Degrés Décimaux).
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=48.85667&lon=2.35194 &appid=${apiKey}&units=metric`;
Pour faire la conversion DMS vers DD il existe beaucoup de convertisseurs en ligne, comme par exemple celui de EDDMaps
Par contre il se peut que le résultat soit légèrement différent de celui obtenu en donnant le nom du lieu
4. Détecter automatiquement votre position
4.1 utiliser Geolocation.getCurrentPosition
HTML5 propose une API JavaScript de géolocalisation pour obtenir la position géographique d'un ordinateur, d'un téléphone ou d'une tablette, ce qui permet aux contenus Web d'accéder à leur localisation. Un site internet ou une application mobile peut alors offrir divers services liés à la localisation de l'utilisateur.
La méthode Geolocation.getCurrentPosition() fournit la position actuelle de l'appareil. Consultez sa documentation puis modifiez votre code pour ne plus afficher la météo de Paris lorsque la page est chargée, mais celle correspondant à la position de votre ordinateur. Le résultat attendu est le suivant
Pour ne pas casser votre travail fait dans l'exercice précédent, faites une copie des fichiers weather1.html et weather.js vers de nouveaux fichiers weather2.html et weather2.js que vous modifierez pour faire cet exercice.
Correction
La méthode Geolocation.getCurrentPosition() qui fournit la position actuelle de l'appareil est une méthode aynchrone, il faut donc intégrer le traitement effectuant la requête à OpenWeather API dans la fonction callback passée en paramètre de l'appel à getCurrentPosition().
Le code de weather2.js
const apiKey = "a08807a5e6c7223bf1c221f8f87580a4";
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?appid=${apiKey}&units=metric`;
const options = {
// les options pour Geolocation.getCurrentPosition
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
navigator.geolocation.getCurrentPosition(success, error, options);
//---------------------------------------------------------------------
// fonctions utilisées par le programme ci-dessus
//---------------------------------------------------------------------
/**
* Fait une requête sur WeatherMap API pour obtenir les conditions météorologiques
* actuelles en un lieu donné et affiche le résultat dans la page HTML
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @param {string} elementId l'id de l'élement HTML où doit être affiché le résultat
*/
function afficherMeteo(latitude, longitude, elementId) {
// Effectuer une requête à l'API OpenWeatherMap
fetch(apiUrl + `&lat=${latitude}&lon=${longitude}`)
.then(response => response.json())
.then(data => {
// Récupérer les données de température et de description du temps
const temperature = data.main.temp;
const description = data.weather[0].description;
// Afficher les données dans la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Vous êtes à (lat=${latitude}, lon=${longitude}).
Il fait actuellement ${temperature} degrés Celsius avec ${description}.`;
})
.catch(error => console.error(error));
}
/**
* Callback pour getCurrentPosition en cas de succès
* @param {Position} pos la position retrouvée
*/
function success(pos) {
let crd = pos.coords;
// trace sur la console
console.log("Votre position actuelle est :");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude : ${crd.longitude}`);
console.log(`La précision est de ${crd.accuracy} mètres.`);
// utiliser les coordonnées obtenues pour récuperer la méto et afficher
// les résultats dans la page Web
afficherMeteo(crd.latitude, crd.longitude, "weather");
}
/**
* Callback pour getCurrentPosition en cas d'échec
* @param {Error} err l'erreur détectée
*/
function error(err) {
// trace sur la console
console.warn(`ERREUR (${err.code}): ${err.message}`);
// affiche un message sur la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Erreur lors de la géolocalisation de votre appareil ${err.message} (code : ${err.code})`;
}
La fonction Geolocation.getCurrentPosition() étant asynchrone, il faut lui transmettre le traitement à effectuer lorsque la géolocalisation est acquise au travers d'une fonction callback. On peut reprocher à cette manière un éventuel manque de clarté, le traitement étant enfoui dans la fonction callback. Une alternative est de transformer cette fonction en une promesse (Promisification en anglais) ce qui donnerait le code suivant.
const apiKey = "a08807a5e6c7223bf1c221f8f87580a4";
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?appid=${apiKey}&units=metric`;
const options = {
// les options pour Geolocation.getCurrentPosition
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
geolocalisation()
.then((coord) => afficherMeteo(coord.latitude, coord.longitude, "weather"))
.catch((err) => {
const weatherElement = document.getElementById('weather');
weatherElement.innerHTML = `Erreur lors de la géolocalisation de votre appareil
${err.message} (code : ${err.code})`;
}
);
//---------------------------------------------------------------------
// fonctions utilisées par le programme ci-dessus
//---------------------------------------------------------------------
/**
* Fait une requête sur WeatherMap API pour obtenir les conditions météorologiques
* actuelles en un lieu donné et affiche le résultat dans la page HTML
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @param {string} elementId l'id de l'élement HTML où doit être affiché le résultat
*/
function afficherMeteo(latitude, longitude, elementId) {
// Effectuer une requête à l'API OpenWeatherMap
fetch(apiUrl + `&lat=${latitude}&lon=${longitude}`)
.then(response => response.json()})
.then(data => {
// Récupérer les données de température et de description du temps
const temperature = data.main.temp;
const description = data.weather[0].description;
// Afficher les données dans la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Vous êtes à (lat=${latitude}, lon=${longitude}).
Il fait actuellement ${temperature} degrés Celsius avec ${description}.`;
})
.catch((error) => {
console.error(error);
});
}
/**
* Permet d'obtenir de manière asynchrone la géolocalisation de l'appareil
* @returns une Promesse qui lorsqu'elle sera résolue (c'est à dire la géolocalisation obtenue)
* aura pour
*/
function geolocalisation() {
return new Promise(function (resolve, reject) {
/**
* Callback pour getCurrentPosition en cas de succès
* @param {GeolocationCoordinates} pos un objet de type GeolocationCoordinates (voir la doc de MDN
* https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates)
*/
function success(pos) {
let crd = pos.coords;
// trace sur la console
console.log("Votre position actuelle est :");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude : ${crd.longitude}`);
console.log(`La précision est de ${crd.accuracy} mètres.`);
// la promesse est tenue on renvoie les coordonnées géographiques
resolve(crd);
}
/**
* Callback pour getCurrentPosition en cas d'échec
* @param {Error} err l'erreur détectée
*/
function error(err) {
// trace sur la console
console.warn(`ERREUR (${err.code}): ${err.message}`);
// affiche un message sur la page HTML
const weatherElement = document.getElementById(elementId);
// la promesse est rompue on renvoie l'erreur
reject(err);
}
navigator.geolocation.getCurrentPosition(success, error, options);
});
}
Vous remarquerez que pour pouvoir accéder aux fonctions callback resolve et reject de la promesse créée les fonctions success et error passées en paramètre de la méthode getCurrentPosition() sont déclarées dans l'executor (la fonction anonyme) passé en paramètre du constructeur de la promesse.
4.2 déterminer le nom du lieu avec l'API de géocodage d'OpenWeather
Plutôt que d'afficher les coordonnées géographiques de l'endroit où votre appareil a été géolocalisé, on souhaiterait afficher le nom du lieu.
Modifiez votre code précédent pour aboutir à ce résultat. Pour obtenir le nom du lieu OpenWeatherMap propose une API de geocodage inversée.
Correction
Pour obtenir le résultat attendu, nous allons refactoriser la méthode afficherMeteo() afin de pouvoir lui faire réaliser deux appels à l'API d'OpenWeather (un pour obtenir les conditions météorologiques, l'autre pour obtenir le nom du lieu associé à votre géolocalisation) et ensuite procéder à l'affichage.
/**
* Fait une requête sur WeatherMap API pour obtenir les conditions météorologiques
* actuelles en un lieu donné et affiche le résultat dans la page HTML
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @param {string} elementId l'id de l'élement HTML où doit être affiché le résultat
*/
function afficherMeteo(latitude, longitude, elementId) {
Promise.all(
[
recupererConditionsMeteo(latitude, longitude),
recupererNomDuLieu(latitude, longitude)
]
).then(function (res) {
// Afficher les données dans la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Vous êtes à ${res[1]}.
Il fait actuellement ${res[0].temperature} degrés Celsius avec ${res[0].description}.`;
});
}
On utilise la méthode statique Promise.all() afin de pouvoir effectuer en parallèle les deux requêtes via OpenWeather API. Les promesses passées en paramètre de cette méthode sont retournées par les fonctions recupererConditionsMeteo et recupererNomDuLieu.
/**
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @returns {Promise} une promesse qui si elle est résolue (fulfilled) a pour
* valeur un objet avec deux attributs
* - temperature : la température en degrés Celsius
* - description : une description (en anglais) des conditions météo
*/
function recupererConditionsMeteo(latitude, longitude) {
return fetch(currentWeatherAPIUrl + `&lat=${latitude}&lon=${longitude}`)
.then( response => response.json())
.then( data => {
// Récupérer les données de température et de description du temps
const temperature = data.main.temp;
const description = data.weather[0].description;
return { temperature, description }
});
}
/**
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @returns {Promise} une promesse qui si elle est résolue (fulfilled) a pour
* valeur le nom du lieu
*/
function recupererNomDuLieu(latitude, longitude) {
return fetch(reverseGeocodingAPIUrl + `&lat=${latitude}&lon=${longitude}`)
.then(response => response.json())
.then(data => data[0].name); // Renvoyer le nom du lieu
}
5. Utiliser l'API de géocodage d'OpenWeather
5.1 Météo en n'importe quel lieu
On veut maintenant permettre à l'utilisateur de consulter la météo pour n'importe quel lieu.
Créez une page HTML weather3.html et le script associé weather3.js afin d'avoir l'affichage et le comportement définis sur la figure ci-dessus.
Correction
Le code HTML weather3.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AWA TP2</title>
<link rel="icon" type="image/png" href="../ukraine-icon.png">
</head>
<body>
<h1>Météo</h1>
<p>
Consultez la météo de la localité de votre choix
</p>
<div>
<label for="">Localité : </label>
<input type="text" id="nom-localite" placeholder="nom de la localité">
<button id="searchBtn">Chercher</button>
</div>
<p id="weather"></p>
<script src="weather3.js"></script>
</body>
</html>
Le code javavascript weather3.js
const apiKey = "a08807a5e6c7223bf1c221f8f87580a4";
const currentWeatherAPIUrl = `https://api.openweathermap.org/data/2.5/weather?appid=${apiKey}&units=metric`;
const geocodingAPIUrl = `https://api.openweathermap.org/geo/1.0/direct?appid=${apiKey}`;
document.getElementById("searchBtn").addEventListener("click", function() {
afficherMeteo(document.getElementById("nom-localite").value, "weather");
} );
//---------------------------------------------------------------------
// fonctions utilisées par le programme ci-dessus
//---------------------------------------------------------------------
/**
* Fait une requête sur WeatherMap API pour obtenir les conditions météorologiques
* actuelles en un lieu donné et affiche le résultat dans la page HTML
* @param {number} latitude latitude du lieu
* @param {string} longitude longitude du lieu
* @param {string} elementId l'id de l'élement HTML où doit être affiché le résultat
*/
function afficherMeteo(name, elementId) {
console.log("name " + name + " elementId" + elementId);
fetch(geocodingAPIUrl + `&q=${name}`)
.then( response => response.json()) // Renvoie les données du résultat de la requête au format JSON
.then(data => {
const latitude = data[0].lat;
const longitude = data[0].lon;
return fetch(currentWeatherAPIUrl + `&lat=${latitude}&lon=${longitude}`)
})
.then(response => response.json())
.then(data => {
// Récupérer les données de température et de description du temps
const temperature = data.main.temp;
const description = data.weather[0].description;
// Afficher les données dans la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `A ${name} il fait actuellement ${temperature}
degrés Celsius avec ${description}.`;
})
.catch( err => {
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Erreur ${err.message}`;
});
}
5.2 Améliorer les messages d'erreur
Que se passe-t-il si le nom de la localité est inconnu ? On voudrait que le programme produise l'affichage suivant
Si nécessaire modifiez votre programme pour obtenir l'affichage ci dessus en cas d'erreur sur le nom de la localité.
Correction
Si l'on prend le programme donné en solution de l'exercice précédent, la vidéo ci-dessous vous montre et vous explique ce qu'il se passe si le nom de la localité n'est pas reconnu
Comme indiqué dans la vidéo explicative précédente il suffit donc de détecter si tableau résultat de la requête à l'API de géocodage inversé est vide ou non. Si il est vide on lance une erreur avec un message explicite pour l'utilisateur.
function afficherMeteo(name, elementId) {
fetch(geocodingAPIUrl + `&q=${name}`)
.then( response => response.json()) // résultat de la requête au format JSON
.then(data => {
if (data.length === 0) {
// le tableau est vide
// aucune localité a été trouvée à ce nom
throw new Error(`Aucune localité connue au nom de ${name}`)
}
const latitude = data[0].lat;
const longitude = data[0].lon;
return fetch(currentWeatherAPIUrl + `&lat=${latitude}&lon=${longitude}`)
})
.then(response => response.json()) // résultat de la requête au format JSON
.then(data => {
// Récupérer les données de température et de description du temps
const temperature = data.main.temp;
const description = data.weather[0].description;
// Afficher les données dans la page HTML
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `A ${name} il fait actuellement ${temperature} degrés Celsius
avec ${description}.`;
})
.catch( err => {
const weatherElement = document.getElementById(elementId);
weatherElement.innerHTML = `Erreur: ${err.message}`;
});
}
6. Combiner Github API et OpenWeather API
Github propose une API permettant d'accéder aux différetnes données d'un utilisateur. Parmi les points d'entrée de cette API l'url https://api.github.com/users/login où login est l'identifiant de l'utilisateur permet de récupérer les informations personnelles publiques d'un utilisateur (nom, image de son avatar, localisation, nombre de followers, nbre de repository publics, ....).
Exercice 1 : tester cette API avec postman pour etudier son comportement et voir les données qu'elle fournit. Vous pouvez essayeer avec différents nom d'utilsiateurs : octocat, gloucklegnou, xscriptus, natemoo-re ...
Une fois que vous avez compris le fonctionnement de l'API users de github, écriver une application qui permet de saisir l'identifiant d'un utilisateur récupérer ses infos publiques github d'en afficher une partie (Avatar, nom, nbre de followers) et si sa localisation est renseignée de récuper les coordonnées géographique puis la météo actuelle dans sa localités et d'afficher ses infromations sur la page, comme indiqué sur la figure ci-dessous.