Start learning free

LESSON 119 OF 173 · BACKEND: PAYMENTS AND OTHER SERVICES

Prices in Another Currency in TypeScript

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 ?. req.query.currency as string | undefined gives "EUR" for /products?currency=EUR, and undefined 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. An object in a constant at the top of the file lives as long as the app runs; give it a type, since an empty {} has no properties TypeScript knows of. Here the same idea remembers customer names, so each one is read from the database only once:

const NAMES: { [customerId: number]: string } = {};

function customerName(customerId: number): string {
  if (NAMES[customerId] === undefined) {
    const row = db.prepare("SELECT name FROM customers WHERE id = ?").get(customerId) as { name: string };
    NAMES[customerId] = row.name;
  }
  return NAMES[customerId];
}

Your code must answer these requests, with every price rounded to 2 decimals (in TypeScript, as in JavaScript, 12 * 0.8 is 9.600000000000001; Math.round rounds to a whole number, so multiply by 100 inside it and divide by 100 outside to get 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 object and an async getRates helper 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 helper and the currency conversion in the /products route.


Hint
Call the supplier only inside the if that finds CACHE.rates still undefined, and return CACHE.rates after it: a function typed Promise<Rates> must return the rates, or tsc stops. Check the currency with Object.hasOwn(rates, currency) before you use rates[currency]: a missing key gives undefined, nothing crashes, and every price would turn into null.


STEP 1 OF 11
    Ctrl + Enter to check

    Svc Currency in TypeScript

    Keep going with TypeScript1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free