This Spring Boot application provides RESTful APIs for fetching foreign exchange rates, converting currencies to EUR, and retrieving available currencies. Exchange rates are fetched from an external API and persisted to a local database on application startup.
- get a list of all available currencies
- get all EUR-FX exchange rates at all available dates as a collection
- get the EUR-FX exchange rate at particular day
- get a foreign exchange amount for a given currencyDto converted to EUR on a particular day
- Java 17
- Spring Boot 3
- H2 In-Memory Database
- JUnit 5
- OpenAPI/Swagger
- Lombok
- On startup, the application triggers a bootstrap loader that fetches:
- All available currencies from Bundesbank API (Metadata).
- Historical exchange rates from the Bundesbank API (data).
- These are stored in an H2 in-memory database.
- A scheduled job handles two main tasks:
- Loads all available currencies and historical exchange rates.
- Uses
@Retryableto retry on transient failures (e.g., network/API issues). - Saves data asynchronously in batches using multithreading.
- Runs daily at 5 AM.
- Assumes Bundesbank API has updated rates for the current day.
- Fetches only today’s exchange rate and persists it.
| Endpoint | Method | Description |
|---|---|---|
/api/currencies |
GET | Get all available currencies |
/api/exchangeRates?currencyCode=XXX&date=YYYY-MM-DD |
GET | Get exchange rates for a currency. If date is not provided, returns all available rates |
/api/convertToEUR?currencyCode=XXX&amount=123.45&date=YYYY-MM-DD |
GET | Converts the given amount to EUR for a specific date |
+-----------------------------+
| ExchangeRateBootstrapLoader|
+-------------+--------------+
|
| fetches data from
v
+---------------------+ +------------------------+
| RestClientUtil | | Bundesbank API |
+---------------------+ +------------------------+
|
v
+-----------------------------+
| ExchangeRateService |
| - getExchangeRates() |
| - getAmountInEUR() |
+-----------------------------+
|
v
+-------------+
| H2 Database |
+-------------+
+-----------------------------+
| CurrencyService |
| - getAllCurrencies() |
+-----------------------------+
|
v
+-------------+
| H2 Database |
+-------------+
All services read/write to the H2 database, making the app lightweight and ideal for demos or testing environments.
- public service provided by the German central bank Bundesbank API Documentation
- Java 11 (will run with OpenSDK 15 as well)
- Maven 3.x
The project was generated through the Spring initializer for Java 11 with dev tools and Spring Web as dependencies. In order to build and run it, you just need to click the green arrow in the Application class in your Intellij CE IDE or run the following command from your project root und Linux or ios.
$ mvn spring-boot:runAfter running, the project, switch to your browser and hit http://localhost:8080/api/currencies. You should see list of currencies
Description: Returns a list of all supported currencies.
Response:
[
{
"code": "USD",
"name": "US Dollar"
},
{
"code": "JPY",
"name": "Japanese Yen"
}
]
Description: Retrieves the EUR exchange rates for a specific currency on a given date or all available dates.
| Param | Type | Required | Description |
|---|---|---|---|
currencyCode |
String | Yes | The 3-letter currency code (e.g., USD) |
date |
String | No | Specific date (yyyy-MM-dd) for historical rate |
Response:
{
"currencyCode": "USD",
"exchangeRates": [
{
"date": "2024-04-15",
"exchangeRate": 1.08
},
{
"date": "2024-04-14",
"exchangeRate": 1.07
}
]
}
Description: Converts a given amount in a foreign currency to its EUR value for a specific date.
| Param | Type | Required | Description |
|---|---|---|---|
currencyCode |
String | Yes | The 3-letter currency code (e.g., USD) |
date |
String | Yes | Specific date (yyyy-MM-dd) for historical rate |
amount |
BigDecimal | Yes | Amount in foreign currency |
Response:
{
"amount": 850,
"exchangeRate": 1.18,
"currencyCode": "EUR",
"date": "2025-04-15"
}
-
Replace H2 DB with MongoDB/PostgreSQL
Use a persistent and production-grade database to retain data beyond app restarts and support scaling. -
Use Redis for Caching
Cache:- Frequently requested exchange rates (especially for the current day)
- Currency lists to reduce DB hits and improve performance
-
Add Integration Tests using Testcontainers
Ensure end-to-end flow validation with actual DBs like PostgreSQL, using containers for reliable testing. -
Implement Retry with Exponential Backoff and Circuit Breaker
Enhance the robustness of API calls to the Bundesbank by using libraries like Resilience4j or Spring Retry with backoff strategies. -
Purpose of Loading Complete Historical Data at Startup (Even if Boot is Slower)
Relying on a public API for every request can slow do~~~~wn response times and introduce instability due to external dependency failures or rate limits.
This design assumes high-frequency usage of the service throughout the day, so loading all historical data into the database on startup ensures: -
Faster data retrieval
-
Minimal runtime dependency on the external API
-
More reliable and performant service overall
-
Future improvement could involve a hybrid approach where:
- Only recent data is loaded eagerly
- Older historical data is lazily loaded or fetched on demand and cached when using Actual Database