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.

Architecture: OSM → Photon → Bun/Hono adapter → edge → consumers

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.