{}const=>[]async()letfn</>var
Development

Currency and unit converter: we make our own in the evening (JS and Python)

Mini-guide for beginners: how to build a currency converter (via API) and units (via coefficients) in JavaScript and Python. Code, checks, ideas for leveling up.

К

Kodik

Author

6 min read

🧭 Plan

  • Mini currency converter in JavaScript (exchange rate cache + offline fallback).

  • Length units converter in JavaScript (without API — only coefficients).

  • Single-file converter in Python (CLI) for practice "in the terminal".

  • UX trifles, tests and development ideas.

Goal: to understand the logic and build a working prototype without heavy frameworks.

🔥 100,000+ students already with us

Tired of reading theory?
Time to code!

Kodik — an app where you learn to code through practice. AI mentor, interactive lessons, real projects.

🤖 AI 24/7
🎓 Certificates
💰 Free
🚀 Start learning
Joined today

💱 Currency converter (JavaScript, browser)

<!-- index.html -->
<div style="max-width:420px;margin:auto;font:16px/1.5 system-ui">
  <h2>Конвертер валют</h2>
  <label>Сумма: <input id="amount" type="number" step="0.01" value="100"></label><br><br>
  <label>Из:
    <select id="from">
      <option>USD</option><option>EUR</option><option>RUB</option>
    </select>
  </label>
  <label>В:
    <select id="to">
      <option>EUR</option><option>USD</option><option>RUB</option>
    </select>
  </label>
  <button id="convert">Перевести</button>
  <p id="out"></p>
</div>

<script>
const cache = { rates: null, ts: 0 };

// Offline stub: if the API is not available, we use fictitious rates
const fallbackRates = { "USD": 1, "EUR": 0.92, "RUB": 92.0 }; // 1 USD = 0.92 EUR, 92 RUB

async function getRates() {
  const now = Date.now();
  if (cache.rates && (now - cache.ts < 10 * 60 * 1000)) return cache.rates;

  try {
    // Replace with the real API of the courses; important: check CORS and the response format.
    // Example:
    // const res = await fetch("https://api.example.com/latest?base=USD");
    // const data = await res.json(); const rates = data.rates;
    // For the demo, we use a stub:
    const rates = fallbackRates;
    cache.rates = rates; cache.ts = now; return rates;
  } catch (e) {
    console.warn("API is not available, we use a stub", e);
    return fallbackRates;
  }
}

function formatMoney(value, code) {
  // Simple formatting; for production, use Intl.NumberFormat
  return `${value.toFixed(2)} ${code}`;
}

document.getElementById('convert').addEventListener('click', async () => {
  const amount = parseFloat(document.getElementById('amount').value);
  const from = document.getElementById('from').value;
  const to = document.getElementById('to').value;
  const out = document.getElementById('out');

  if (Number.isNaN(amount) || amount < 0) {
    out.textContent = "Please enter a valid amount (≥ 0).";
    return;
  }
  if (from === to) {
    out.textContent = formatMoney(amount, to);
    return;
  }

  const rates = await getRates();
  if (!rates[from] || !rates[to]) {
    out.textContent = "The selected currency is not supported.";
    return;
  }

  // We convert to the base currency (USD) and then to the target currency
  const inUSD = amount / rates[from];     // how much USD in the original amount
  const converted = inUSD * rates[to];    // translated into the target
  out.textContent = formatMoney(converted, to);
});
</script>

What's happening: we take the number, the currency "from", the currency "to", pull up the rates (from the API or from fallbackRates) and convert the amount through the base currency USD: from → USD → to.

  • 10-minute cache: cache stores the rates and time stamp to avoid spamming the API and speed up the response.

  • Offline mode: if the network/server is unavailable, use fallbackRates — the demo always works.

  • Validation: we cut off NaN and negative amounts, and in the case of "from=to" we simply show the original value.

  • Formatting: The formatMoney function rounds to 2 digits. For production, take Intl.NumberFormat under the user's locale.

💡 Improvement: add auto recalculation for the event input and save the currency selection in localStorage.

📏 Unit converter (JavaScript, no API)

<!-- units.html -->
<div style="max-width:420px;margin:auto;font:16px/1.5 system-ui">
  <h2>Конвертер единиц (длина)</h2>
  <label>Значение: <input id="val" type="number" step="0.0001" value="1"></label><br><br>
  <label>Из:
    <select id="uFrom">
      <option>m</option><option>cm</option><option>km</option><option>ft</option><option>in</option>
    </select>
  </label>
  <label>В:
    <select id="uTo">
      <option>cm</option><option>m</option><option>km</option><option>ft</option><option>in</option>
    </select>
  </label>
  <button id="go">Конвертировать</button>
  <p id="res"></p>
</div>

<script>
// coefficients to METER
const length = {
  m: 1,
  cm: 0.01,
  km: 1000,
  ft: 0.3048,
  in: 0.0254
};

function convert(value, from, to, table) {
  if (!(from in table) || !(to in table)) throw new Error("Unit not supported");
  const base = value * table[from];     // in meters
  return base / table[to];              // to the target unit
}

document.getElementById('go').addEventListener('click', () => {
  const value = parseFloat(document.getElementById('val').value);
  const from = document.getElementById('uFrom').value;
  const to = document.getElementById('uTo').value;
  const res = document.getElementById('res');

  if (Number.isNaN(value)) { res.textContent = "Enter a number."; return; }
  if (from === to) { res.textContent = `${value} ${to}`; return; }

  const out = convert(value, from, to, length);
  res.textContent = `${out.toFixed(4)} ${to}`;
});
</script>

Idea: one "base" unit is a meter. In the table, each unit has a coefficient of "how many meters in 1 unit". Then the formula is the same: value × coefficientFrom → meters → / coefficientTo.

  • Checking supported units: we throw an explicit error instead of a "silent" NaN.

  • Rounding: we do at the very end (toFixed(4)) so as not to accumulate error.

  • Extension: the "mass/volume/speed" categories work in the same way; temperature - through formulas, not coefficients.

💡 Take out the dictionaries of units in units.js and load them by the selected category.

🐍 Single-file converter (Python, CLI)

# convert.py
from dataclasses import dataclass

RATES = {"USD": 1.0, "EUR": 0.92, "RUB": 92.0}  # replace with real ones if necessary
UNITS_LEN = {"m":1, "cm":0.01, "km":1000, "ft":0.3048, "in":0.0254}

@dataclass
class Result:
  value: float
  unit: str

def convert_currency(amount: float, from_code: str, to_code: str) -> Result:
  if from_code not in RATES or to_code not in RATES:
    raise ValueError("Currency is not supported")
  in_usd = amount / RATES[from_code]
  out = in_usd * RATES[to_code]
  return Result(round(out, 2), to_code)

def convert_length(value: float, from_u: str, to_u: str) -> Result:
  if from_u not in UNITS_LEN or to_u not in UNITS_LEN:
    raise ValueError("Unit not supported")
  base = value * UNITS_LEN[from_u]
  out = base / UNITS_LEN[to_u]
  return Result(round(out, 4), to_u)

def main():
  print("Converter: 1) Currency 2) Length")
  mode = input("Select mode (1/2): ").strip()
  if mode == "1":
    a = float(input("Amount: "))
    fc = input("From currency (USD/EUR/RUB): ").strip().upper()
    tc = input("In currency (USD/EUR/RUB): ").strip().upper()
    res = convert_currency(a, fc, tc)
    print(f"→ {res.value} {res.unit}")
  elif mode == "2":
    v = float(input("Value: "))
    fu = input("From (m/cm/km/ft/in): ").strip()
    tu = input("In (m/cm/km/ft/in): ").strip()
    res = convert_length(v, fu, tu)
    print(f"→ {res.value} {res.unit}")
  else:
    print("Unknown mode")

if __name__ == "__main__":
  main()

Approach: "pure" functions return Result and do not print — they are easy to test. In main() only input/output.

  • Currency conversion: the scheme is the same as in JS: we convert to USD, then to the target currency. Rounding only at the end.

  • Length conversion: we use the dictionary of coefficients to the meter. The formula remains the same for all units.

  • Money accuracy: if you need financial accuracy, use decimal.Decimal instead of float.

💡 Move the conversion to a separate module and cover it with unit tests; leave the CLI thin.

UX little things that make it convenient

  • Auto recalculation for event input (without button).

  • Saving the "from/to" selection in localStorage.

  • Copying the result: navigator.clipboard.writeText.

  • For currencies — Intl.NumberFormat under the user's locale.

Tests and rakes

  • Round off at the very end; compare numbers with tolerance (epsilon).

  • Convert temperatures using formulas (not coefficients).

  • When working with the API, check CORS, limits, and refresh rate.

In Codice we make programming training fun and easy to understand: we have interesting courses with tasks that help you improve your skills step by step.

And we also have an active Telegram channel, where we discuss cool ideas, share experiences and analyze tasks together — learning becomes not only useful, but also fun.

🎯Stop procrastinating

Liked the article?
Time to practice!

In Kodik, you don't just read — you write code immediately. Theory + practice = real skills.

Instant practice
🧠AI explains code
🏆Certificate

No registration • No card