Start learning free

LESSON 119 OF 173 · BACKEND: PAYMENTS AND OTHER SERVICES

Prices in Another Currency

Practice

Customers abroad want prices in their own money. The shop's prices are in US dollars, and the supplier publishes exchange rates at GET /rates: {"USD": 1.0, "EUR": 0.9, "GBP": 0.8}, how many euros or pounds one dollar is worth. A product of 12 dollars costs 12 × 0.9 = 10.8 euros.

The client picks a currency in the query string, the part of the URL after the ?. The parameter @RequestParam(required = false) String currency is "EUR" for /products?currency=EUR, and null when the URL has no currency.

Rates change slowly, so asking the supplier again for every list would only make the shop slower. Ask once and keep the answer in the app's memory: a cache. A static final map in the controller lives as long as the app runs. Here the same idea remembers customer names, so each one is read from the database only once:

static final Map<Integer, String> NAMES = new HashMap<>();

String customerName(int customerId) {
    if (!NAMES.containsKey(customerId)) {
        String name = db.queryForObject("SELECT name FROM customers WHERE id = ?", String.class, customerId);
        NAMES.put(customerId, name);
    }
    return NAMES.get(customerId);
}

Your code must answer these requests, with every price rounded to 2 decimals (in Java, 12 * 0.8 is 9.600000000000001, and Math.round(x * 100) / 100.0 makes it 9.6):

GET /products                →  200  [{"id": 1, "name": "Mug", "price": 12, …}, …]
GET /products?currency=EUR   →  200  [{"id": 1, "name": "Mug", "price": 10.8, …}, …]
GET /products?currency=GBP   →  200  [{"id": 1, "name": "Mug", "price": 9.6, …}, …]
GET /products?currency=JPY   →  400  {"error": "Unknown currency"}

The plain list never calls the supplier, and the three currency requests together call its /rates only once.

Your task: add a CACHE map and a getRates method that asks the supplier only the first time. Then make GET /products convert every price when a currency is given, and answer 400 for a currency the supplier has no rate for.


Assignment
Follow the Coding Tutorial to add the cache, the getRates method and the currency conversion in getProducts.


Hint
Call the supplier only inside if (!CACHE.containsKey("rates")). Check the currency with containsKey before you use rates.get(currency): a missing rate is null, and casting it to double would crash the request with a 500. Java compiles getRates only once it ends with its return.


STEP 1 OF 12
    Ctrl + Enter to check