City Fetcher API
Prompt
You have two async APIs that provide geographic data:
getStates(country)returns a promise resolving to an array of state codes (e.g.['CA', 'NY', 'WA'])getCities(state)returns a promise resolving to an array of city names for that state
Implement a function getAllCities(country) that:
- Fetches all states for the given country
- Fetches cities for every state in parallel
- Returns a promise resolving to a single flat array of all city names
Playground
Start by awaiting getStates(country) to get the list of
state codes. Once you have the array, think about how to
fetch cities for all of them without waiting for each
one individually.
Use .map() on the states array to call getCities for
each state. This gives you an array of promises. Pass that
array to Promise.all to run all the requests in
parallel.
Promise.all resolves to an array of arrays (one city
array per state). You need a single flat list. Look into
the .flat() array method.
Solution
Explanation
This problem is about composing asynchronous operations. You have two APIs that each return a promise, and your job is to wire them together so one feeds into the other.
The first step is straightforward: call getStates(country) and await the result. You get back an array of state codes like ['CA', 'NY', 'WA']. Nothing tricky here.
The interesting part comes next. You need to call getCities for every state, and each call returns a promise. The naive approach would be to loop through the states one by one, awaiting each call sequentially. That works, but it's slow. If you have 50 states, you're waiting for 50 network requests to complete one after another.
The better approach is to fire all the requests in parallel using Promise.all. You .map() over the states array, calling getCities on each one. This gives you an array of promises. You hand that array to Promise.all, which waits for all of them to resolve and gives you back an array of results:
const citiesPerState = await Promise.all(
states.map((state) => getCities(state))
);
// [['LA', 'SF', 'SD'], ['LA1', 'SF1', 'SD1'], ['LA2', 'SF2', 'SD2']]At this point you have an array of arrays. Each inner array is the list of cities for one state. You need a flat list, so you call .flat() to collapse it into a single array.
The place where candidates most commonly get stuck is the flattening step. They'll get the nested array from Promise.all and forget that they need to combine those inner arrays. If your output looks like [['LA', 'SF'], ['NYC', 'Buffalo']] instead of ['LA', 'SF', 'NYC', 'Buffalo'], that's the issue.
Promise.all preserves the order of results. Even though
the requests run in parallel and may finish at different
times, the resolved array always matches the order of the
input promises. That's why the cities come back in state
order.