Skip to content

bobwallis/ReverseGeocoder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ReverseGeocoder

ReverseGeocoder is a self-hosted geolocation toolkit for village-level lookups. It provides:

  • reverse geocoding (lat/lon → nearest place)
  • text geocoding (q → matching places)
  • IP to country (IPv4/IPv6 → ISO-3166 country code)

It is designed as a lightweight alternative to commercial geolocation APIs when village-level detail is precise enough, and avoiding massive credit card bills is preferred.

I use it to convert the location data provided by the Geolocation API into a human-readable location on isitgoingtorain.com, and to do the location search on the same site.

Repository map

  • data/: data acquisition and transformation pipeline
  • php/: PHP endpoint implementation
  • aws/: AWS Lambda + Serverless implementation
  • AGENTS.md: contribution playbook for coding agents

First 30 minutes

You can get from clone to a working lookup in about half an hour or so.

  1. Build the dataset and database using data/README.md.
  2. Pick a runtime:
  3. Call one endpoint to verify behavior.

API

All runtimes implement the same three GET endpoints:

  • /reverse_geocode?lat=<lat>&lon=<lon>
  • /geocode?q=<query>&prefer_country=<ISO2 optional>
  • /ip2country?ip=<ip optional>

GET /reverse_geocode?lat=<lat>&lon=<lon>

Required query parameters:

  • lat: decimal latitude in the range -90 to 90
  • lon: decimal longitude in the range -180 to 180

Behavior:

  • returns 400 if either coordinate is missing or out of range
  • searches for nearby places using an approximately 8km bounding box
  • handles longitude wrap-around at ±180
  • returns the closest matching place if one is found
  • returns a fallback name of <lat>, <lon> if no nearby place is found

Example:

/reverse_geocode?lat=51.7546&lon=-1.2588

Typical successful response:

{
   "name": "Oxford",
   "admin": "Oxfordshire, England",
   "country": "GB",
   "latitude": 51.752,
   "longitude": -1.258
}

GET /geocode?q=<query>&prefer_country=<ISO2 optional>

Required query parameters:

  • q: text search term

Optional query parameters:

  • prefer_country: 2-letter ISO-3166 country code used to narrow/prioritize results

Behavior:

  • returns 400 if q is missing
  • returns 400 if prefer_country is present but invalid
  • matches place names by prefix and substring
  • ranks matches using place.sort descending within match groups
  • returns up to 10 results

Example:

/geocode?q=oxfo&prefer_country=GB

Typical successful response:

[
   {
      "name": "Oxford",
      "admin": "Oxfordshire, England",
      "country": "GB",
      "latitude": 51.752,
      "longitude": -1.258
   }
]

GET /ip2country?ip=<ip optional>

Optional query parameters:

  • ip: IPv4 or IPv6 address

Behavior:

  • when ip is supplied, looks up that address and returns a cacheable result
  • when ip is omitted, the runtime falls back to the request/client IP by whatever route that runtime has available
  • returns 400 for invalid IP input
  • supports both IPv4 and IPv6 range lookups
  • returns country: null when no matching range is found

Example:

/ip2country?ip=2001:4860:4860::8888

Typical successful response:

{
   "ip": "2001:4860:4860::8888",
   "country": "US"
}

For runtime-specific setup and operational notes, see:

Data model

place

Column Data Type Description
country char(2) ISO-3166 2-letter country code
name text Name of the point
admin integer ID of the administrative area of the point
sort integer Bigger = higher priority when searching
latitude decimal(6,3) Latitude in decimal degrees (WGS84)
longitude decimal(6,3) Longitude in decimal degrees (WGS84)

admin

Column Data Type Description
id integer ID column
name text Name of the administrative area

ip

Column Data Type Description
network_start integer Decimal IP address starting a range
network_end integer Decimal IP address ending a range
country char(2) ISO-3166 2-letter country code of the range

ipv6

Column Data Type Description
network_start text Expanded IPv6 address starting a range
network_end text Expanded IPv6 address ending a range
country char(2) ISO-3166 2-letter country code of the range

The included pipeline builds these from GeoNames and GeoLite2 data sources.

Documentation index

Data licensing and sources

About

A simple reverse geocoder

Topics

Resources

License

Stars

Watchers

Forks

Contributors