Coding Challenge Where Am I
A real coding challenge: turn GPS coordinates into a rendered country card, chaining two completely different APIs with everything from the last several posts.
Everything from the last several posts, fetch, chaining, throwing to reject a Promise on purpose, getJSON, adds up to something worth actually building, not just reading about.
The Challenge
Write a function whereAmI(lat, lng) that takes GPS coordinates and:
- Reverse-geocodes those coordinates into a city and country (turning a latitude/longitude pair into a real place name)
- Logs
You are in {city}, {country} - Looks up and renders that country, the same way every post since post 2 has
- Handles errors from both API calls
One constraint worth keeping: build the geocoding half with a raw fetch().then().catch(), no getJSON there, that would skip the actual practice. The country half can reuse getJSON freely.
Test it against three real coordinate pairs: 52.508, 13.381, 19.037, 72.873, and -33.933, 18.474.
Try it before reading past this point. What follows is one way to build it, not the only way.
Building the Geocoding Half
A reverse-geocoding API takes coordinates and answers with a place. This one needs no key and allows cross-origin requests.
fetch('https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=52.508&longitude=13.381&localityLanguage=en')
.then((res) => res.json())
.then((data) => console.log(`You are in ${data.city}, ${data.countryName}`));Run that and it works, right up until it doesn't. This API rate-limits aggressively, and just like the 404 from the last post, a rate-limit response is still a completed request as far as fetch is concerned, still fulfilled, res.ok still the only signal anything went wrong.
ExpandA rejection propagates down through the chain until something catches it, whether that rejection came from a real network failure or a manual throw.
Same fix as last post, applied to a second, unrelated API:
fetch('https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=52.508&longitude=13.381&localityLanguage=en')
.then((res) => {
if (!res.ok) throw new Error(`Problem with geocoding (${res.status})`);
return res.json();
})
.then((data) => console.log(`You are in ${data.city}, ${data.countryName}`))
.catch((error) => console.error(`๐ฅ ${error.message}`));Chaining Into the Country Lookup
The geocoded data.countryName slots straight into the exact same country lookup every earlier post already built, so this half gets to reuse getJSON instead of rewriting it.
Hit Run and Berlin resolves to Germany, rendered as a full country card, from nothing but a pair of numbers. Two completely different APIs, chained through one function, with a single .catch() covering both.
Try whereAmI(19.037, 72.873) next (Mumbai), and worth knowing honestly: a country search is a substring match, not an exact one, so a query like "India" can match more than one country and this code takes whichever comes first. That's a real limitation of the search, not a bug in the chain.
The Essentials
- A working solution chains two unrelated APIs through the exact same pattern: fetch, check
ok, throw or parse, catch at the end. - A second API can fail the same way the first one did. Rate limits, like 404s, still leave
fetchfulfilled,res.okis what actually tells the story. - Reusing
getJSONfor the half that repeats a known pattern, and writing the new half by hand, is exactly how much repetition is worth wrapping. - A single
.catch()at the end of the whole chain still covers every step, geocoding and country lookup alike. - An API's search behavior (like substring matching) is worth checking directly, not assuming, when a result looks unexpected.
Keep reading