Skip to content
← 1001 Widgets
N° 023 · ●●○

Currency converter

Euro, Swiss franc, Canadian dollar: a converter at the daily rate published by the European Central Bank. The right exercise to call an API and plan for when it does not answer.

JSAPI
What you'll learn
  • Load rates with fetch
  • Compute a cross rate from the euro
  • Plan a fallback when the network fails
Why this language

Pourquoi un convertisseur de devises ? Entre la Belgique, la Suisse et le Canada, on jongle sans cesse entre euros, francs et dollars. Un convertisseur au taux du jour évite les approximations.

Les taux viennent de Frankfurter, une API gratuite et sans clé qui republie ceux de la Banque centrale européenne. Tous sont donnés par rapport à l'euro : pour convertir des francs en dollars, on passe par l'euro avec une simple division.

Pourquoi en JavaScript simple ? Un fetch, un objet de taux, une division. Et surtout, une solution de repli si l'API ne répond pas.

How it works
  1. LE HTML

    <input id="montant" inputmode="decimal" value="100">
    <select id="de"></select> <select id="vers"></select>
    <output id="resultat"></output>
  2. LES TAUX

    Frankfurter renvoie tous les taux par rapport à l'euro.

    let taux = { EUR: 1 };
    async function chargerTaux() {
      const r = await fetch('https://api.frankfurter.dev/v1/latest?from=EUR&to=CHF,CAD,USD,GBP');
      if (!r.ok) throw new Error('Taux indisponibles');
      const data = await r.json();
      taux = { EUR: 1, ...data.rates };
    }
  3. LE TAUX CROISÉ

    De CHF vers USD : on passe par l'euro.

    const tauxEntre = (a, b) => taux[b] / taux[a];
  4. LIRE UN MONTANT À LA FRANÇAISE

    « 1 250,50 » doit devenir 1250.5.

    const lire = t => Number(t.replace(/\s/g, '').replace(',', '.'));
  5. CONVERTIR

    function convertir() {
      const montant = lire(document.getElementById('montant').value);
      const a = document.getElementById('de').value, b = document.getElementById('vers').value;
      const fmt = new Intl.NumberFormat('fr-BE', { style: 'currency', currency: b });
      document.getElementById('resultat').textContent =
        isNaN(montant) ? 'Montant invalide' : fmt.format(montant * tauxEntre(a, b));
    }
    
    chargerTaux().catch(() => { taux = { EUR: 1, CHF: 0.94, CAD: 1.6, USD: 1.16, GBP: 0.86 }; }).finally(convertir);
Pitfalls

PIÈGE 1 : Oublier la virgule

Pitfall

Mauvais : Number('12,50'). Le résultat vaut NaN, alors qu'en Belgique c'est ainsi qu'on écrit.

Fix

Correct : retirer les espaces et remplacer la virgule par un point avant de convertir.

PIÈGE 2 : Une page blanche hors ligne

Pitfall

Mauvais : ne rien prévoir si fetch échoue. Le convertisseur reste vide sans explication.

Fix

Correct : un catch qui charge des taux indicatifs, et un message qui le dit clairement.

PIÈGE 3 : Recharger à chaque frappe

Pitfall

Mauvais : appeler l'API à chaque modification du montant. Des dizaines de requêtes pour des taux qui changent une fois par jour.

Fix

Correct : charger les taux une fois, puis calculer localement.

PERSONNALISER
  • Une liste de devises favorites en haut du menu.
  • L'historique sur 30 jours avec l'adresse /v1/2025-01-01..?from=EUR de la même API.
  • Un mode voyage : le montant saisi dans la devise locale s'affiche directement en euros.
OPTIMISATION
  • Gardez les taux en cache dans localStorage avec leur date, et ne rechargez que le lendemain.
  • Les taux de la BCE sont publiés vers 16 h : avant cette heure, ce sont ceux de la veille.
VERS REACT

Les taux se chargent dans un useEffect au premier rendu, avec un état de chargement et un état d'erreur.

Le montant et les deux devises vivent dans des useState, le résultat se calcule pendant le rendu.

Pour une vraie application, une bibliothèque comme TanStack Query gère le cache et les nouvelles tentatives.

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.