APIs, langages de transmission de données et requêtes asynchrones

Prévisions météo

Dans ce TP, pour illustrer le recours à un langage de transmission de données (ici, json) et l’utilisation de requêtes asynchrones, nous allons réaliser une petite application de prévision météorologiques.

https://openweathermap.org/API

Pour pouvoir utiliser cette API, il faut un jeton d’identification. Pour cela, nous allons créer un compte (Create an Account) sur https://home.openweathermap.org/users/sign_in. Premier essai, téléchargeons et interprétons ce que renvoie https://api.openweathermap.org/data/2.5/weather?q=Nancy,France&appid=??? (mettre le jeton d’identification à la place des ???.

Nous obtenons un tableau de tableaux dont les index sont des chaînes de caractères (tableau associatif).

Par exemple

{
 "sys": {
  "sunset": 1372275728,
  "country": "FR",
  "sunrise": 1372217655
 },
 "main": {
  "temp": 14,
  "pressure": 1029,
  "temp_max": 14,
  "humidity": 71,
  "temp_min": 14
 },
 "coord": {
  "lon": 6.2000000000000002,
  "lat": 48.683331000000003
 },
 "wind": {
  "speed": 2.6000000000000001,
  "var_end": 50,
  "deg": 350,
  "var_beg": 310
 },
 "weather": [
  {
   "id": 802,
   "description": "nuages éparses",
   "main": "Clouds",
   "icon": "03d"
  }
 ],
 "base": "global stations",
 "dt": 1372233600,
 "clouds": {
  "all": 48
 },
 "id": 2990999,
 "name": "Nancy",
 "cod": 200
}

Firefox permet d’afficher le JSON soit en mode arborescent (lisible, joli), soit en mode texte (RAW).

  1. À l’aide de la documentation, modifier la query string de l’URL de la requête pour avoir des unités “métriques” (degrés Celsius, km/h…) et la langue française dans les réponses du serveur.

  2. Pour commencer dans un fichier meteop.js, créer une variable (nommée par exemple donneesMeteo) contenant ce tableau.

  3. Comment peut-on accéder au nom de la ville ? À la température ? À la description du temps ?

  4. Créer une page web meteop.html qui affiche une boîte de dialogue de la forme

    À Nancy, la température est de 14 degrés avec nuages épars.

  5. Dans la console, afficher chaque clef du tableau associatif automatiquement (coord, weather, base, …)

  6. Pour actualiser les données sans modifier à la main le javascript, nous allons utiliser la technique jsonp qui consiste à définir la source du fichier json comme un nouveau script et à ajouter un callback à la fonction qui utilise les données.

    1. Fonctionnaliser le javascript pour avoir une fonction interpreteMeteo prenant pour argument donneesMeteo.

    2. Supprimer la variable globale donneesMeteo. Seule doit demeurer dans le fichier js la fonction.

    3. Dans la page html, ajouter

      <script src="https://api.openweathermap.org/data/2.5/weather?q=Paris,France&appid=???&callback=interpreteMeteo"></script>

      et tester cette nouvelle version.

      Explications : en ajoutant cette ligne script, nous permettons au navigateur de télécharger les données météo courantes, donc d’avoir des données à jour. Pour indiquer à l’interprète javascript ce qu’il doit faire du fichier json téléchargé, nous ajoutons &callback=interpreteMeteo, le callback donnant la fonction à appliquer aux données obtenues. Cette technique (fichier json dans une balise script adjointe d’un callback) est nommée jsonp pour json padding.

  7. (Optionnel) Créer un formulaire dans lequel entrer un nom de ville et où l’appui sur un bouton indiquera la météo dans la ville en question.

Requêtes asynchrones

Outre jsonp, une autre technique permet de charger des données issues d’un site tiers : l’utilisation de requêtes asynchrones. L’asynchronie signifie que notre script n’a pas se bloquer en attendant le résultat du site distant mais continuer à travailler et repousser le traitement de ce fragment au moment où il arrivera.

La requête se fera à l’aide de fetch :

var url = "https://api.openweathermap.org/data/2.5/weather?q=Paris,France&appid=???"
var promesse = fetch(url)
var jsonprom = promesse.then(function(r) {return r.json()})
jsonprom.then(interprete)

La ligne 2 crée la requête et stocke la “promesse de résultat” dans la variable promesse. La 3 convertit cette promesse en promesse de json. La ligne 4 indique que quand cette promesse de json sera satisfaite, on la passera à la procédure interprete.

function interprete (data) {
	// traite les données json obtenue par fetch
	console.log(data)
}

Note : la syntaxe typique utilisée pour fetch ne passe pas par des variables intermédiaires (promesse et jsonprom) mais enchaîne les then. De plus la conversion en json utilise souvent la fonctionalisation avec => au lieu de function.

fetch(url).then(r => r.json()).then(interprete)
  1. Dans de nouveaux fichiers meteo.html et meteo.js, utiliser cette technique pour obtenir les mêmes résultats que dans l’exercice précédent.
  2. Créer un formulaire dans lequel entrer un nom de ville et où l’appui sur un bouton indiquera la météo dans la ville en question.

DOM scripting

Plutôt qu’une alerte, nous voudrions modifier le contenu de la page dynamiquement, c’est-à-dire modifier le code html. On parle de modification du DOM (Document Object Model) ou de DOM-scripting. Le langage javascript, tournant dans les navigateur, dispose de nombreuses fonctions et procédures pour manipuler les documents HTML ou XML.

Fonction ou procédure Entrée Sortie Rôle
document.createElement(b) b : chaine e : élément HTML Crée un élément html de balise b
document.getElementById(i) i : chaine e : élément HTML Renvoie l’élément de la page ayant pour id i
document.getElementsByClassName(c) c : chaine t : tableau d’éléments HTML Renvoie les éléments de la page ayant pour class c
document.getElementsByTagName(t) t : chaine u : tableau d’éléments HTML Renvoie les éléments de la page de balise t
e.setAttribute(x, y) e : élément HTML; x, y: chaines Met l’attribut x de l’élément e à la valeur y
e.appendChild(f) e, f : élément HTML Ajoute l’élément f aux fils de e

Ces diverses fonctions et procédures permettent de créer, trouver et modifier le contenu d’une page HTML programmatiquement. On remarquera que les deux dernières procédures ont une entrée placée avant le nom de la fonction. Cette syntaxe est en fait dérivée des dictionnaires, en effet, les éléments HTML sont des dictionnaires ayant des clefs setAttribute et appendChild et le contenu des cases ayant ces clefs sont des procédures. On utilisera également le champ innerHTML des éléments html pour directement assigner à leur contenu une chaîne de caractères. À l’aide de ces fonctions, on peut par exemple créer un fichier html quasiment vide et le faire remplir par un script javascript.

Par exemple, considérons le contenu html suivant :

<!doctype html>
<html lang="fr">
<head><meta charset="utf-8" />
      <title>DOM Scripting</title>
</head>
<body>
<h1 class="titre"></h1>
<h2 class="titre"></h2>
<div id="contenu"></div>
<script src="remplissage.js"></script>
</body>

Sans exécution de javascript, cette page est vide. En ajoutant le code javascript suivant, la page va se remplir.

var titres, divc, paragraphe, i

titres = document.getElementsByClassName("titre")
for (i = 0; i<titres.length; i = i+1) {
    titres[i]["innerHTML"] = "Nouveau titre " + String(i)
}
divc = document.getElementById("contenu")
paragraphe = document.createElement("p")
paragraphe.setAttribute("class", "vert")
paragraphe["innerHTML"] = "Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur. Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit."
divc.appendChild(paragraphe)

Et le code html de la page que va afficher le navigateur ressemblera à ce qui suit :

<!DOCTYPE html>
<html lang="fr"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="utf-8">
      <title>DOM Scripting</title>
</head>
<body>
<h1 class="titre">Nouveau titre 0</h1>
<h2 class="titre">Nouveau titre 1</h2>
<div id="contenu"><p class="vert">Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur. Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.</p></div>
<script src="remplissage.js"></script>
</body></html>
  1. Tester le code ci-dessus. Constater la différence entre le source de la page et ce qu’affiche l’inspecteur html.

  2. Modifier la page de l’exercice précédent pour que les données météorologiques de la ville choisie soient affichées dans un tableau html par exemple comme suit.

    Ville Nancy
    Température 14
    Pression 1029
    Humidité 74
    Vitesse du vent 2.6000002
    Direction du vent 350

Autre application

Je souhaite maintenant afficher un classement de D1 de Futsal sur ma page web. Pour cela, je vais utiliser https://cygne.hainry.fr/cours/r209/futsald1.json.

  1. Tester la requête suivante :

    var url = "https://cygne.hainry.fr/cours/r209/futsald1.json"
    fetch(url).then(r => r.json()).then(console.log)

    Explorer les résultats de requêtes auprès de ce site.

  2. Créer une page web sur laquelle est affiché le classement de D1. En utilisant les styles, rendre le tableau joli. Vous utiliserez la méthode des requêtes asynchrones.

    Vous devriez obtenir un résultat conforme à l’image suivante :

    ligue2

    En particulier, faites en sorte que votre équipe préférée apparaisse de façon éclatante.

  3. Créer une page web donnant les informations sur l’équipe de Guingamp. En particulier le calendrier des matches futurs et les résultats des matches passés doit apparaître de façon adéquate.

  4. Modifier cette page web de façon à ce que l’utilisateur puisse choisir son équipe favorite dans une liste déroulante (balise select) et voir toutes les informations.

Références