Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
JavaScript

Interroger une API publique (exemple : météo)

Suivez une démarche complète pour utiliser une API publique avec l'exemple d'Open-Meteo : choix de l'API, lecture de la documentation, test de l'adresse, exploration du JSON (tableaux parallèles, unit...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

Suivez une démarche complète pour utiliser une API publique avec l'exemple d'Open-Meteo : choix de l'API, lecture de la documentation, test de l'adresse, exploration du JSON (tableaux parallèles, unités), fonction fetch, page de météo de cinq villes tunisiennes en parallèle avec Promise.allSettled, sécurité des clés d'API avec un relais PHP, quotas, cache et attribution, autres API publiques. Avec des activités corrigées.
  1. Objectifs

    • Suivre une démarche complète pour utiliser une API publique : choisir, lire la documentation, tester, coder, afficher.
    • Lire une documentation d'API et construire une requête avec ses paramètres.
    • Explorer et exploiter une réponse JSON réelle (objets, tableaux parallèles, unités).
    • Interroger plusieurs lieux en parallèle avec Promise.allSettled.
    • Respecter les règles d'usage : clés d'API, quotas, cache, attribution.
  2. Les API publiques

    • Des milliers d'organismes mettent des données à disposition par des API web : météo, cartes, transports, taux de change, livres, données publiques des États (open data), etc. Les utiliser permet de créer des applications riches sans produire soi-même ces données.
    • Elles diffèrent par leurs conditions d'accès:
    Type d'accèsExempleUtilisable directement depuis une page ?
    Libre, sans cléOpen-Meteo (météo), JSONPlaceholder (données de test)Oui, si CORS est autorisé
    Avec clé d'API gratuiteDe nombreux services météo, cartographiques ou financiersNon : la clé serait visible. Passer par son serveur
    Avec authentification de l'utilisateur (OAuth)Agenda, messagerie, réseaux sociauxOui, après connexion de l'utilisateur
    PayanteDonnées boursières, traduction, IANon : toujours via son serveur
    • Pour ce cours, nous utilisons Open-Meteo: service européen de prévisions, gratuit pour un usage non commercial, sans inscription ni clé, qui autorise les appels depuis une page web (CORS). Ses données sont sous licence CC BY 4.0 : il faut citer la source.

    Les cinq étapes pour interroger une API publique, exemple Open-Meteo et sécurité des clés d'API

  3. Étape 1 : choisir l'API

  4. Avant d'écrire une ligne de code, vérifiez :

  • Les données: contient-elle ce dont j'ai besoin (température actuelle, prévisions heure par heure, sur combien de jours, pour la Tunisie) ?
  • L'accès: clé obligatoire ? CORS autorisé ? HTTPS ?
  • Les limites: nombre de requêtes par minute ou par jour (les dépasser donne une erreur 429).
  • Les conditions: usage commercial permis ? attribution obligatoire ?
  • La fiabilité: documentation claire, service maintenu, versions de l'API.
  • Étape 2 : lire la documentation

    • La documentation d'Open-Meteo (open-meteo.com/en/docs) propose un formulaire qui construit l'adresse pour vous : choisissez un lieu et des variables, et l'URL apparaît en bas de page. Les principaux paramètres :
    ParamètreExempleRôle
    latitude, longitude36.8065, 10.1815Le lieu (Tunis), obligatoires
    currenttemperature_2m,weather_codeVariables de la météo actuelle
    hourlytemperature_2m,precipitation_probabilityVariables heure par heure
    dailytemperature_2m_max,temperature_2m_minVariables par jour
    timezoneautoHeures exprimées dans le fuseau du lieu
    forecast_days7Nombre de jours de prévision
    temperature_unitfahrenheitUnité (Celsius par défaut)
    • Le temps est décrit par un code WMO (Organisation météorologique mondiale) : 0 = ciel dégagé, 3 = couvert, 61 = pluie faible, 95 = orage… La documentation en donne la liste complète, à traduire en texte et en icône.
    • Une seconde API, Geocoding (https://geocoding-api.open-meteo.com/v1/search?name=Sfax&count=1&language=fr), transforme un nom de ville en coordonnées : elle servira dans le TP 19.
  • Étape 3 : tester l'adresse

    • Collez cette adresse dans votre navigateur (Firefox et Chrome affichent le JSON de façon lisible) :
    https://api.open-meteo.com/v1/forecast?latitude=36.8065&longitude=10.1815&current=temperature_2m,weather_code,wind_speed_10m&daily=temperature_2m_max,temperature_2m_min&timezone=auto&forecast_days=3
    • Vous obtenez une réponse de cette forme (valeurs d'exemple) :
    {
      "latitude": 36.8125,
      "longitude": 10.1875,
      "timezone": "Africa/Tunis",
      "current_units": { "temperature_2m": "°C", "wind_speed_10m": "km/h" },
      "current": {
        "time": "2026-11-12T21:45",
        "temperature_2m": 17.6,
        "weather_code": 3,
        "wind_speed_10m": 18.4
      },
      "daily_units": { "temperature_2m_max": "°C", "temperature_2m_min": "°C" },
      "daily": {
        "time": ["2026-11-12", "2026-11-13", "2026-11-14"],
        "temperature_2m_max": [21.2, 19.1, 18.4],
        "temperature_2m_min": [13.1, 12.5, 11.9]
      }
    }
    • current est un objet simple. daily (et hourly) contient des tableaux parallèles: l'indice 1 de chaque tableau concerne le même jour (le 13 novembre, max 19,1 °C, min 12,5 °C).
    • Les unités sont fournies à part (current_units, daily_units) : affichez-les plutôt que de les écrire en dur.
    • Les coordonnées renvoyées diffèrent un peu de celles demandées : le modèle calcule sur une grille et renvoie le point le plus proche.
    • Faites une erreur volontaire (latitude=999) : l'API répond 400 avec un message d'explication en JSON. Prévoyez ce cas dans le code.
    1. Étape 4 : coder la requête

    2. async function meteoActuelle(latitude, longitude) {
        const params = new URLSearchParams({
          latitude,
          longitude,
          current: "temperature_2m,weather_code,wind_speed_10m",
          timezone: "auto",
        });
        const reponse = await fetch(`https://api.open-meteo.com/v1/forecast?${params}`, {
          signal: AbortSignal.timeout(8000),
        });
        if (!reponse.ok) {
          throw new Error(`Service météo : erreur ${reponse.status}`);
        }
        const donnees = await reponse.json();
        return donnees.current; // on ne garde que ce qui sert
      }
      
      const meteo = await meteoActuelle(36.8065, 10.1815);
      console.log(`${meteo.temperature_2m} °C, vent ${meteo.wind_speed_10m} km/h`);
    • Le code reprend tout ce que nous avons vu : URLSearchParams, délai maximal, test de reponse.ok, lecture du JSON. La fonction renvoie seulement les données utiles, pour que le reste de l'application ne dépende pas de la structure exacte de l'API.
  • Étape 5 : exemple complet, la météo de cinq villes

  • La page affiche la météo actuelle de cinq villes tunisiennes. Les cinq requêtes partent en même temps; si l'une échoue, les autres s'affichent quand même grâce à Promise.allSettled.

    index.html:

    <!doctype html>
    <html lang="fr">
      <head>
        <meta charset="utf-8" />
        <title>Météo des villes tunisiennes</title>
        <link
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.9/dist/css/bootstrap.min.css"
          rel="stylesheet"
        />
        <script type="module" src="meteo.js"></script>
      </head>
      <body class="container py-4" style="max-width: 640px">
        <h1 class="h3">🌍 Météo en Tunisie</h1>
        <p class="text-body-secondary" id="etat">Chargement…</p>
        <table class="table">
          <thead>
            <tr>
              <th>Ville</th>
              <th>Temps</th>
              <th class="text-end">Température</th>
              <th class="text-end">Vent</th>
            </tr>
          </thead>
          <tbody id="tableau"></tbody>
        </table>
        <p class="small">
          Données : <a href="https://open-meteo.com/" target="_blank" rel="noopener">Open-Meteo.com</a>
        </p>
      </body>
    </html>

    meteo.js:

    const VILLES = [
      { nom: "Tunis", latitude: 36.8065, longitude: 10.1815 },
      { nom: "Sfax", latitude: 34.7406, longitude: 10.7603 },
      { nom: "Sousse", latitude: 35.8256, longitude: 10.6084 },
      { nom: "Gabès", latitude: 33.8815, longitude: 10.0982 },
      { nom: "Tozeur", latitude: 33.9197, longitude: 8.1335 },
    ];
    
    const DESCRIPTIONS = {
      0: "☀️ Dégagé",
      1: "🌤️ Peu nuageux",
      2: "⛅ Nuageux",
      3: "☁️ Couvert",
      61: "🌦️ Pluie",
    };
    
    function urlMeteo({ latitude, longitude }) {
      const params = new URLSearchParams({
        latitude,
        longitude,
        current: "temperature_2m,weather_code,wind_speed_10m",
        timezone: "auto",
      });
      return `https://api.open-meteo.com/v1/forecast?${params}`;
    }
    
    async function meteoDe(ville) {
      const reponse = await fetch(urlMeteo(ville), { signal: AbortSignal.timeout(8000) });
      if (!reponse.ok) {
        throw new Error(`HTTP ${reponse.status}`);
      }
      const donnees = await reponse.json();
      return { ...ville, ...donnees.current };
    }
    
    function cellule(texte, classe = "") {
      const td = document.createElement("td");
      td.className = classe;
      td.textContent = texte;
      return td;
    }
    
    const debut = performance.now();
    // 5 requêtes en parallèle ; allSettled attend la fin de TOUTES, même en cas d'échec
    const resultats = await Promise.allSettled(VILLES.map(meteoDe));
    const duree = Math.round(performance.now() - debut);
    
    const lignes = resultats.map((resultat, i) => {
      const tr = document.createElement("tr");
      if (resultat.status === "fulfilled") {
        const meteo = resultat.value;
        tr.append(
          cellule(meteo.nom, "fw-semibold"),
          cellule(DESCRIPTIONS[meteo.weather_code] ?? `Code ${meteo.weather_code}`),
          cellule(`${Math.round(meteo.temperature_2m)} °C`, "text-end"),
          cellule(`${Math.round(meteo.wind_speed_10m)} km/h`, "text-end"),
        );
      } else {
        tr.append(
          cellule(VILLES[i].nom, "fw-semibold"),
          cellule(`Indisponible (${resultat.reason.message})`),
        );
      }
      return tr;
    });
    document.getElementById("tableau").replaceChildren(...lignes);
    
    const reussies = resultats.filter((resultat) => resultat.status === "fulfilled").length;
    document.getElementById("etat").textContent =
      `${reussies}/${VILLES.length} villes chargées en ${duree} ms.`;
    • Promise.allSettled renvoie, pour chaque promesse, un objet { status: "fulfilled", value } ou { status: "rejected", reason }: on affiche les données ou un message d'indisponibilité, ville par ville.
    • performance.now() mesure la durée totale : environ celle de la requête la plus lente, et non la somme des cinq.
    • La source des données est citée en bas de page, comme l'exigent les conditions d'Open-Meteo.
  • Les clés d'API : jamais dans le JavaScript

    • Beaucoup d'API exigent une clé, une chaîne secrète qui identifie votre compte (et vos quotas, voire votre facture). Tout ce qui est dans le JavaScript d'une page est public: n'importe qui peut lire la clé dans le code source ou l'onglet Réseau, et l'utiliser à votre place.
    // ❌ À NE PAS FAIRE : la clé est visible par tous (code source, onglet Réseau)
    fetch(`https://api.service-meteo.com/data?q=Tunis&appid=8f3a1c2e9b7d4f60a5e1c3b2d9f8e7a6`);
    
    // ✅ Le navigateur appelle VOTRE serveur, qui ajoute la clé (gardée dans un fichier .env)
    fetch("/api/meteo?ville=Tunis");
    • La solution : un petit relais (proxy) sur votre serveur. Le navigateur appelle votre serveur, qui ajoute la clé (rangée dans une variable d'environnement, jamais dans Git) et renvoie la réponse. Exemple en PHP :
    <?php
    // api/meteo.php – petit relais (proxy) côté serveur : la clé ne quitte jamais le serveur
    $ville = urlencode($_GET['ville'] ?? 'Tunis');
    $cle = getenv('METEO_API_KEY');
    $reponse = file_get_contents("https://api.service-meteo.com/data?q=$ville&appid=$cle&lang=fr");
    header('Content-Type: application/json');
    header('Cache-Control: max-age=600'); // le navigateur peut réutiliser la réponse 10 minutes
    echo $reponse;
    • Bonus : le serveur peut mettre les réponses en cache et limiter le nombre d'appels, ce qui protège aussi vos quotas.
    • Si une clé a été publiée par erreur (dans un dépôt GitHub par exemple), elle doit être considérée comme compromise : révoquez-la et créez-en une nouvelle.
  • Respecter l'API : quotas, cache, attribution

    • Quotas : chaque API limite le nombre de requêtes. Ne lancez pas une requête à chaque frappe au clavier : attendez une pause de saisie de 300 ms (technique du debounce, TP 19 et chapitre 23) et annulez les requêtes devenues inutiles.
    • Erreur 429 : si vous la recevez, attendez avant de réessayer (l'en-tête Retry-After indique parfois combien de secondes).
    • Cache : la météo change peu en quelques minutes ; gardez la dernière réponse en mémoire ou dans le localStorage (chapitre 20) au lieu de rappeler l'API.
    • Attribution : citez la source avec un lien, comme demandé par la licence.
    • Robustesse : une API externe peut être lente, en panne ou modifier son format. Prévoyez un message clair et un affichage dégradé, et ne laissez jamais une page entière dépendre d'un seul appel.
  • D'autres API publiques pour s'entraîner

  • APIDonnéesAccès
    Open-MeteoMétéo, qualité de l'air, géocodage, historiqueLibre, sans clé
    JSONPlaceholderFaux utilisateurs, articles, tâches (pour les tests)Libre, sans clé
    Open LibraryLivres, auteurs, couverturesLibre, sans clé
    FrankfurterTaux de change publiés par la Banque centrale européenneLibre, sans clé
    Nager.DateJours fériés par pays (dont la Tunisie)Libre, sans clé
    • Avant de les utiliser, appliquez la démarche : documentation, test de l'adresse, conditions d'usage. Les services gratuits évoluent : vérifiez qu'ils sont toujours actifs.
  • Activités

  • Activité 1 : explorer l'API

    • Avec le formulaire de la documentation d'Open-Meteo, construisez l'adresse qui donne pour Sousse la température maximale et minimale et la somme des précipitations des 5 prochains jours. Testez-la dans le navigateur.
    • Quelle est la température maximale prévue après-demain ? À quel indice des tableaux se trouve-t-elle ?
    • Que renvoie l'API si vous oubliez le paramètre longitude?

    Activité 2 : les cinq villes

    • Dans le dossier api-meteo de votre dépôt js-ajax-fetch, reproduisez l'exemple complet.
    • Complétez la table DESCRIPTIONS avec tous les codes WMO de la documentation.
    • Ajoutez une colonne « Demain » avec la température maximale du lendemain (paramètre daily).
    • Ajoutez un bouton « Actualiser » et l'heure de la dernière mise à jour.

    Activité 3 : une autre API

    • Avec l'API Nager.Date (https://date.nager.at/api/v3/PublicHolidays/2027/TN), affichez la liste des jours fériés en Tunisie pour 2027, avec la date au format « samedi 20 mars 2027 » (Intl.DateTimeFormat) et le nombre de jours restant avant chacun.

    Activité 4 : questions

    • Pourquoi ne faut-il jamais écrire une clé d'API dans le JavaScript d'une page ? Que faire à la place ?
    • Dans la réponse d'Open-Meteo, comment retrouver la température minimale du 3e jour ?
    • Quelle est la différence entre Promise.all et Promise.allSettled? Laquelle convient pour la page des cinq villes, et pourquoi ?
    • Que signifie une réponse 429?
    Corrigés. Activité 1 : …/forecast?latitude=35.8256&longitude=10.6084&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=auto&forecast_days=5; après-demain se trouve à l'indice 2 ; sans longitude, l'API répond par une erreur 400 accompagnée d'un message. Activité 2 : pour « Demain », ajoutez daily: "temperature_2m_max" et lisez donnees.daily.temperature_2m_max[1]. Activité 4 : elle serait visible par tout le monde et pourrait être utilisée à vos frais ; passer par un relais sur son serveur ; donnees.daily.temperature_2m_min[2]; Promise.all échoue dès qu'une requête échoue, Promise.allSettled attend tous les résultats ; allSettled, pour afficher les villes disponibles même si l'une est en erreur ; trop de requêtes, quota dépassé.
  • À retenir

    • Démarche : choisir l'API, lire la documentation, tester l'adresse, coder avec fetch, afficher en gérant chargement et erreurs.
    • Explorez toujours le JSON avant de coder ; attention aux tableaux parallèles et aux unités.
    • Promise.allSettled pour plusieurs requêtes indépendantes qui peuvent échouer séparément.
    • Jamais de clé d'API dans le JavaScript ; respectez quotas, cache et attribution.

    Sources : MDN Web Docs, WHATWG (XMLHttpRequest, Fetch), IETF, open-meteo.com.