Skip to content
← 1001 Widgets
N° 013 · ●●●

Weather

Live weather for a city, with no API key, thanks to Open-Meteo. The right exercise to learn to wait for a network response and handle its errors.

HTMLJSAPI
What you'll learn
  • Call an API with fetch and async/await
  • Chain two requests: the city, then the weather
  • Show a clear error when the network fails
Why this language

Pourquoi un widget météo ? C'est la première rencontre avec une API : on envoie une requête, on attend, on reçoit du JSON, et on gère le cas où rien n'arrive.

On utilise Open-Meteo, une API gratuite et sans clé : parfait pour apprendre sans créer de compte.

Pourquoi en JavaScript simple ? fetch, async et await suffisent. Le reste, c'est de l'affichage.

How it works
  1. LE HTML

    <form id="recherche">
      <input id="ville" value="Bruxelles">
      <button>Voir</button>
    </form>
    <p id="meteo" aria-live="polite"></p>
  2. TROUVER LA VILLE

    Open-Meteo a deux API : une pour transformer un nom de ville en coordonnées, une pour la météo.

    async function coordonnees(nom) {
      const r = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(nom)}&count=1&language=fr`);
      if (!r.ok) throw new Error('Recherche indisponible');
      const data = await r.json();
      if (!data.results) throw new Error('Ville introuvable');
      return data.results[0];
    }
  3. LIRE LA MÉTÉO

    async function meteo({ latitude, longitude }) {
      const r = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,weather_code,wind_speed_10m`);
      if (!r.ok) throw new Error('Météo indisponible');
      return (await r.json()).current;
    }
  4. TRADUIRE LE CODE MÉTÉO

    L'API renvoie un numéro par type de temps.

    const CIELS = { 0: 'Ciel dégagé', 1: 'Plutôt dégagé', 2: 'Partiellement nuageux', 3: 'Couvert', 45: 'Brouillard', 61: 'Pluie', 71: 'Neige', 80: 'Averses', 95: 'Orage' };
  5. TOUT ASSEMBLER

    try / catch attrape aussi bien une ville introuvable qu'une coupure réseau.

    document.getElementById('recherche').addEventListener('submit', async e => {
      e.preventDefault();
      const sortie = document.getElementById('meteo');
      sortie.textContent = 'Chargement…';
      try {
        const lieu = await coordonnees(document.getElementById('ville').value);
        const m = await meteo(lieu);
        sortie.textContent = `${lieu.name} : ${Math.round(m.temperature_2m)} °C, ${CIELS[m.weather_code] ?? 'temps variable'}, vent ${Math.round(m.wind_speed_10m)} km/h`;
      } catch (err) {
        sortie.textContent = err.message;
      }
    });
Pitfalls

PIÈGE 1 : Oublier que le réseau peut échouer

Pitfall

Mauvais : un fetch sans try / catch. Hors connexion, le widget reste bloqué sur « Chargement ».

Fix

Correct : try / catch autour des appels, et un message clair.

PIÈGE 2 : Croire que fetch échoue sur une erreur 500

Pitfall

Mauvais : se fier au catch seul. fetch ne lève une erreur que si le réseau tombe : une réponse 404 ou 500 passe sans bruit.

Fix

Correct : tester r.ok avant de lire le JSON.

PIÈGE 3 : Coller le texte tapé dans l'URL

Pitfall

Mauvais : ?name=${nom}. Une ville avec une espace ou un & casse la requête.

Fix

Correct : encodeURIComponent(nom).

PERSONNALISER
  • Une icône par code météo : un objet qui associe chaque code à un petit SVG.
  • La position du visiteur avec navigator.geolocation, après lui avoir demandé la permission.
  • Les degrés Fahrenheit avec &temperature_unit=fahrenheit dans l'URL.
OPTIMISATION
  • Gardez la dernière réponse en mémoire dix minutes : la météo ne change pas à chaque clic.
  • Annulez la requête précédente avec AbortController si l'utilisateur relance une recherche.
VERS REACT

Trois états : chargement, données, erreur. Un useEffect lance la requête quand la ville change, et l'annule au nettoyage.

Pour plusieurs widgets qui lisent la même API, une bibliothèque de cache comme TanStack Query évite les requêtes en double.

Variants
Comments
0/1000

Loading comments…

Audience measurement

With your consent, this site measures its traffic with Google Analytics and the Meta pixel, via Google Tag Manager. Nothing is loaded until you choose, and you can change your mind at any time with the "Cookies" link at the bottom of the page.