Geocoding — turning "jalan tun razak" into coordinates and a structured address — is a solved problem with unsolved pricing. The big providers charge per lookup forever. The open alternative, Photon, is excellent — but its raw API wasn't the contract we wanted to promise people.
So address.xwira.tech is two services wearing one trench coat.
The engine: Photon
Photon is an open-source geocoder built on OpenStreetMap data with a Lucene index — forward search, reverse geocoding, typo tolerance, multilingual labels. We run it from a prebuilt index; it happily serves the whole planet from one well-fed container.
Crucially, Photon never faces the internet. It has no auth model of its own, and exposing a raw JVM search service publicly is how you end up in someone's botnet postmortem. It listens only inside the cluster network.
The adapter: 300 lines that earn their keep
In front sits a small Bun + Hono service that does four things:
1. Shape. Photon speaks GeoJSON — nested features[].properties with OSM-flavored keys. Useful, but nobody wants to teach their frontend OSM taxonomy. The adapter flattens every result to one stable shape:
{
"name": "Menara Kuala Lumpur",
"street": "Jalan Punchak",
"city": "Kuala Lumpur",
"country": "Malaysia",
"lat": 3.1528,
"lng": 101.7038
}
2. Contract. If Photon's response format shifts in an upgrade — or we swap the engine entirely — the public API doesn't move. The adapter is the API; the geocoder is an implementation detail. That's the whole pattern.
3. Guardrails. API-key auth for programmatic use, a browser-origin guard for the public demo, per-client rate limits, strict CORS. The heavy engine only ever sees clean, already-vetted queries.
4. Translation of intent. Endpoints named for what people want — /search, /reverse — with input validation that returns helpful 400s instead of Lucene stack traces.
The deployment
Same platform as the rest of the xwira stack: containers on self-hosted Kubernetes, Traefik at the edge with auto-issued TLS, manifests in version control. The OSM index sits on a persistent volume — rebuilding it is a scheduled job, not an emergency.
The takeaway
If you're wrapping any third-party engine — a geocoder, an LLM, a payments API — the adapter isn't overhead, it's the product. It's where your naming, your stability promise, and your security posture live. Photon does the hard computer science; the adapter does the hard product work.
Try it: address.xwira.tech — search any address on Earth.