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.

July 11, 20264 min read11 / 22Exercise

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.

JavaScript ยท Live Editor
Loading editor...

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.

JavaScript
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.

A rejection propagates down through the chain until something catches it, whether that rejection came from a real network failure or a manual throw. 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:

JavaScript
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.

JavaScript ยท Live Editor
Loading editor...

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

  1. A working solution chains two unrelated APIs through the exact same pattern: fetch, check ok, throw or parse, catch at the end.
  2. A second API can fail the same way the first one did. Rate limits, like 404s, still leave fetch fulfilled, res.ok is what actually tells the story.
  3. Reusing getJSON for the half that repeats a known pattern, and writing the new half by hand, is exactly how much repetition is worth wrapping.
  4. A single .catch() at the end of the whole chain still covers every step, geocoding and country lookup alike.
  5. An API's search behavior (like substring matching) is worth checking directly, not assuming, when a result looks unexpected.