Build a Currency Converter Using Fetch API and Exchange Rates
Creating a real-time currency converter is an excellent way to deepen your understanding of JavaScript, APIs, and user interface dynamics. In this guide, we’ll walk through how to build a simple currency converter using JavaScript’s Fetch API and a free currency exchange rate API.
This project demonstrates several key web development skills: using Fetch to retrieve data from a RESTful API, updating the DOM in response to user interaction, handling asynchronous code gracefully, and applying basic performance best practices. By the end, you’ll have a functioning currency converter you can build upon and deploy.
1. Setting Up the Project Structure
First, let’s create a minimal but well-structured HTML and JavaScript foundation for our app.
// index.html
Currency Converter
Currency Converter
We provide a simple UI with an input field for the amount, two dropdowns for currency selection, and a button to trigger the conversion. Now let’s wire it up with JavaScript.
2. Fetching the Exchange Rate Data
We’ll use the free ExchangeRate.host API, which provides reliable exchange rates with no API key required. We’ll use the endpoint https://api.exchangerate.host/latest
to fetch current conversion rates.
// script.js
const fromCurrency = document.getElementById("from");
const toCurrency = document.getElementById("to");
const amountInput = document.getElementById("amount");
const convertButton = document.getElementById("convert");
const resultField = document.getElementById("result");
// Populate dropdowns
fetch("https://api.exchangerate.host/symbols")
.then((res) => res.json())
.then((data) => {
const symbols = data.symbols;
for (let code in symbols) {
let option1 = new Option(`${code} - ${symbols[code].description}`, code);
let option2 = option1.cloneNode(true);
fromCurrency.appendChild(option1);
toCurrency.appendChild(option2);
}
fromCurrency.value = "USD";
toCurrency.value = "EUR";
});
We initially call the /symbols
endpoint to retrieve all available currencies and fill both dropdown menus. This makes the converter dynamic and scalable for any currency.
3. Performing the Currency Conversion
Now, let’s add the logic that performs the conversion when the user clicks the convert button. We’ll construct the API URL based on selected currencies and the amount, then display the result.
convertButton.addEventListener("click", () => {
const from = fromCurrency.value;
const to = toCurrency.value;
const amount = parseFloat(amountInput.value);
if (isNaN(amount) || amount <= 0) {
resultField.textContent = "Please enter a valid amount.";
return;
}
const url = `https://api.exchangerate.host/convert?from=${from}&to=${to}&amount=${amount}`;
fetch(url)
.then((res) => res.json())
.then((data) => {
let result = data.result.toFixed(2);
resultField.textContent = `${amount} ${from} = ${result} ${to}`;
})
.catch((error) => {
console.error("Error fetching conversion:", error);
resultField.textContent = "Conversion failed. Try again later.";
});
});
This script triggers a new API call every time the button is clicked. It validates the input, constructs the URL with query parameters, parses the JSON response, and updates the result field.
4. Improving UX and Performance
You can improve the user experience and avoid unnecessary fetch calls or re-renders by optimizing input handling:
- Debounce user input for rapid typing.
- Use loading indicators during async calls.
- Disable the convert button until currencies are fully loaded.
An example of adding a simple loading state could be:
convertButton.disabled = true;
// Enable button when dropdowns are populated
fetch("https://api.exchangerate.host/symbols")
.then((res) => res.json())
.then((data) => {
// Fill dropdowns as before...
convertButton.disabled = false;
});
This ensures that users can’t trigger conversion before all necessary data is available, reducing confusion and server load.
5. Optional: Handle Rate Caching to Improve Speed
Instead of calling the API for every conversion, you can cache the full exchange rate table once at page load, and then do client-side math:
let rates = {};
fetch("https://api.exchangerate.host/latest?base=USD")
.then((res) => res.json())
.then((data) => {
rates = data.rates;
});
convertButton.addEventListener("click", () => {
const from = fromCurrency.value;
const to = toCurrency.value;
const amount = parseFloat(amountInput.value);
if (!rates[from] || !rates[to]) return;
const usdAmount = amount / rates[from];
const convertedAmount = usdAmount * rates[to];
resultField.textContent = `${amount} ${from} = ${convertedAmount.toFixed(2)} ${to}`;
});
This technique reduces API load and speeds up conversions but risks having stale rates if used for long sessions. Consider a hybrid approach by refreshing rates periodically.
Conclusion
Congratulations! You now have a working live currency converter powered by JavaScript and the Fetch API. We retrieved exchange rates from a public API, handled JSON responses, manipulated the DOM dynamically, and added UX improvements.
Here’s how this example can be further enhanced:
- Use localStorage to persist last used selections
- Style with CSS for responsive layouts
- Add historical conversion charts with Chart.js
- Convert multiple currencies at once
APIs like exchangerate.host make it easy to build real-world apps without a backend. Keep experimenting, and you’ll master asynchronous data and client-side logic in no time!
Useful links: