Backend

Geocoding Bad Matches Fail Safely

Geocoding APIs will happily return a result for almost any query, including city-level matches for a neighbourhood and coordinates in the wrong state. This build constrains the lookup to a bounding box and rejects partial matches, so an unresolvable place returns nothing rather than a wrong location.

· The RECNOS Engineering Team

The failure mode is a plausible wrong answer

A geocoder that returns a result for every query is worse than one that sometimes returns nothing. Given an ambiguous locality name, the API returns the most likely match — which may be a different city entirely, or a city-level centroid standing in for a neighbourhood.

Downstream, that coordinate is used to compute distances and find nearby places. A wrong coordinate does not throw an error. It silently produces a list of nearby localities on the other side of the country.

Constrain the search area

The lookup is bounded to a rectangle around the service area. Coordinates are passed as `bounds`, along with `region` and a country component, so the API ranks results inside the area first.

The result is then checked against the same box in code. A coordinate outside the rectangle is discarded even though the API considered it a valid answer.

const BBOX = { south: 12.7, west: 77.35, north: 13.25, east: 77.85 };

Reject partial matches at the wrong granularity

The API flags approximate matches with `partial_match`. That flag alone is not enough to reject on — some partial matches are useful. The check that matters is the combination: a partial match whose result types include a locality or an administrative area means the geocoder fell back to a coarser answer than the one requested.

A neighbourhood query that resolves to a city centroid is exactly the case that produces a plausible but wrong coordinate, so it is rejected.

Return null, never throw

Every failure path returns `null`: no API key, empty input text, a partial match at the wrong granularity, or a coordinate outside the bounding box. No branch throws.

That choice pushes the handling to the caller, which is where the decision belongs. A locality with no coordinate still renders; it simply does not participate in distance sorting, and the sort falls back to list order.

Cache on the right assumption

Results are cached for 30 days, on the reasoning that a place's coordinates do not move. That is a different assumption from the one you would make for a price or a listing count, and it is worth stating explicitly because it justifies a much longer window than most cached data would get.

The bounding box is a constant in the source rather than configuration. That is correct while the product serves one city, and would need to become per-region data before a second city is added.

The project this came from