A practical assignment for the Python Advanced course.
- Develop an asynchronous microservice to get the exchange rate of a given currency against a fixed set of target currencies.
- Add support for specifying a date in the request.
- Store cache on disk to reduce unnecessary API calls.
- Use
aiohttp serverto create the asynchronous web application. - Use
aiohttp clientfor making asynchronous network requests. - Use
aiofilesto work with files asynchronously (read/write).
You can use any public API to retrieve exchange rates.
A free option: fawazahmed0/currency-api
-
✅ List of available currencies:
https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies.json -
✅ Exchange rate for a given currency (latest):
https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/{currency}.json
Example:https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/eur.json -
✅ Exchange rate for a given currency on a specific date:
Replacelatestwith a date inISO-8601format:
https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@{date}/v1/currencies/{currency}.json
Example:https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@2024-09-28/v1/currencies/rub.json
- Define a static list of target currencies to which the exchange rate should be returned.
Create a wrapper for handling API requests:
- Use
aiohttp clientfor network communication. - Implement a high-level method to fetch the exchange rate for a selected currency and date.
- Add a method to read from cache (disk).
- If a cached value exists for the currency and date — return it without making network requests.
- On the first API call, build a response object from the fetched data and save it to disk in a pre-defined cache directory.
Develop a web application using aiohttp server:
- Implement a single route handler to retrieve exchange rate data.
- Support queries both with and without a date.
- If no date is provided, use today’s date.
- Use the API wrapper to get data:
- If the data is cached — use the cached result.
- If it’s a new request — fetch, format, and save to cache before responding.
- If an unknown currency is provided — return HTTP 404.
- If an invalid date is provided — return HTTP 422.
- Add type annotations throughout the codebase.
- Ensure the application passes
mypychecks in strict mode.
- aiohttp – asynchronous HTTP server and client
- aiofiles – async file I/O
- msgspec – fast data validation and serialization
- python-dotenv – load environment variables from
.envfiles - redis – Redis client for Python
- aioresponses – mock HTTP responses for
aiohttp - coverage – code coverage reports
- fakeredis – in-memory fake Redis server for testing
- mypy – static type checker
- ruff – fast Python linter & formatter
- types-aiofiles – type stubs for
aiofiles
- ✅ Wrote unit tests using Python's standard
unittestmodule - ✅ Added optional Redis-based caching alongside disk caching
git clone https://github.com/bizoxe/exchange-rate-web-app.gitdocker compose up -duv run webapp- get exchange rates for a currency (latest): http://localhost:8080/rates/usd
- get exchange rates for a currency on a specific date: http://localhost:8080/rates/usd/2025-01-01
Note:
You can use file-based caching instead of Redis. In this case, you don’t need to run Docker.
Use the following command to switch to file caching:
export STORAGE_TYPE=fileThen simply run the application with:
uv run webapp