Skip to content

Documentation

Service architecture

The demo separates its HTTP surface from the data service. The browser sends requests to geonames-global-demo; that Worker validates the demo’s HTTP parameters and calls geonames-global-service through the GEONAMES Service Binding. The service owns the D1 database and SEARCH_CACHE KV namespace. The browser and demo Worker do not connect to either store directly.

Browser
│ /api/search, /api/get, /api/get-many, /api/countries, /api/continents
▼
geonames-global-demo (HTTP validation and response adaptation)
│ GEONAMES Service Binding (typed RPC)
▼
geonames-global-service (RPC methods and cache policy)
├── SEARCH_CACHE KV (search pages only)
└── DB D1 (locations and reference tables, including countries)

The catalog routes /api/countries and /api/continents call countries() and continents() over the same internal RPC binding. countries() reads every country/territory reference row from the existing countryInfo.txt import, regardless of search scope or which location rows exist; existing reference imports need no migration. continents() returns the fixed seven-continent catalog without querying D1. The browser catalog page fetches only when Fetch is clicked. These HTTP adapters return plain arrays; they are not public provider endpoints. See catalog API details and the Countries page.

The Service Binding is internal Worker RPC, not a public service URL. Caller and provider need to be in the same Cloudflare account. Provider fetch() returns 404; configure a binding in the caller and use RPC. Deploy the provider first; see the binding and TypeScript interface. Consumers own authentication and authorization for incoming requests. The demo’s public lookup routes are unauthenticated; its admin status and settings routes require a bearer token.

Search options include a configured default country, explicit country/admin1/admin2 filters, and parentId scope. Admin code filters must form a complete hierarchy: admin1 requires country; admin2 requires country and admin1. Parent scope resolves a real GeoNames location and returns only strict descendants. Explicit scopes do not inherit default-country/global-fallback behavior. The default India-first query falls back globally only after the full India query has zero matches; an empty later page does not cause fallback. Scope/configuration identity is part of cache isolation (search:v6).

featureClass P populated places now have highest feature-class priority. Ranking changes are isolated from old cache entries. Search default-scope settings are persisted in service D1; GET/PUT /api/admin/search-settings are protected on the demo Worker, while the operational admin snapshot remains read-only. Apply migration apps/service/migrations/0003_search_settings.sql before deploying the service.

GET /api/search validates HTTP parameters and calls searchPage. The service reads current D1 settings, then checks KV before running search work. A HIT skips parent resolution and search-engine queries; a MISS or BYPASS runs scoped D1 search. Eligible misses await a KV write. KV failure does not fail a successful search. D1 failures propagate and become HTTP 502; invalid scope options become HTTP 400. Timing/cache headers and response metadata are documented under search and API.

get and getMany read D1 directly and do not use the search cache. The service resolves each place’s country, first- and second-level administrative names, and feature metadata through left joins to reference tables. Missing reference rows therefore produce null names/descriptions without making the place itself disappear. Coordinates are stored as integer millionths of a degree and converted to decimal degrees for the returned record. A missing get ID returns null; getMany omits missing IDs while preserving the order and duplicates of found IDs. See the API response contract.

The result is a flat Location object, not a recursively nested administrative hierarchy. countryCode, admin1Code, and admin2Code identify hierarchy levels; resolved names are included alongside them. Admin1 reference keys join as countryCode.admin1Code, and admin2 keys as countryCode.admin1Code.admin2Code. Gaps in the reference data mean the corresponding name can be null. There is no recursive parent/ancestor API.

The service database owns the locations table and the countries, admin1_codes, admin2_codes, and feature_codes reference tables. allCountries.zip (containing allCountries.txt) supplies worldwide places and aliases. The other four imported inputs are countryInfo.txt, admin1CodesASCII.txt, admin2Codes.txt, and featureCodes_en.txt. The separate GeoNames alternate-name V2 dataset is not imported; do not interpret aliases as that dataset. The locations import is the source for place aliases used by search. The import runbook documents the generated chunks and safe local/remote D1 sequence.

The service Wrangler configuration binds D1 as DB and KV as SEARCH_CACHE. Consumer Workers need only a Service Binding; they must not copy database credentials/configuration or recreate service-owned cache policy. Deploy data migrations and service changes before dependent callers. For integrating another Worker, start with the RPC methods, types, validation differences, and error boundaries.