Check whether a geographic coordinate is on water (seas, lakes, and rivers). Exposed via an HTTP API for single coordinate (GET /api/water?lat=${lat}&lon=${lon}) and batch (POST /api/water with { "coordinates": [{ lat, lon }, ...] }) lookups.
Built on Fastify with optional OpenTelemetry, Swagger at /documentation, and rate limiting (in-memory by default; Redis when REDIS_URL is set).
git clone https://github.com/osbytes/is-on-water
cd is-on-water
pnpm install
## run in development with hot-reload
pnpm dev
## OR build and run
pnpm build && pnpm startSee .env-example for all environment variables.
Rate limiting uses an in-memory store by default (no Redis required).
To share limits across multiple instances, set REDIS_URL (for example redis://localhost:6379). You can start Redis with:
docker compose --profile redis upWhen REDIS_URL is set, /health also pings Redis and returns 503 if it is unreachable.
Disabled by default. Enable with OTEL_ENABLED=true.
By default the trace exporter writes to standard output. Set OTEL_EXPORTER_OTLP_ENDPOINT (for example http://localhost:4318/v1/traces) to export to a collector. docker compose up starts Jaeger; UI at http://localhost:16686.
Interactive docs: /documentation
Errors use RFC 9457 Problem Details (application/problem+json).
curl "http://localhost:3000/api/water?lat=20.112682&lon=-37.048647"{ "water": true, "lat": 20.112682, "lon": -37.048647 }Latitude must be between -90 and 90; longitude between -180 and 180.
Body: { "coordinates": [{ "lat", "lon" }, ...] } (max MAX_BATCH_SIZE, default 500). A bare JSON array is also accepted.
curl -X POST http://localhost:3000/api/water \
-H 'content-type: application/json' \
-d '{"coordinates":[{"lat":20.112682,"lon":-37.048647},{"lat":40.292097,"lon":-98.613164}]}'{
"results": [
{ "water": true, "lat": 20.112682, "lon": -37.048647 },
{ "water": false, "lat": 40.292097, "lon": -98.613164 }
]
}Water polygons are stored as gzip-compressed FlatGeobuf in data/waterbodies.fgb.gz, built from @geo-maps/earth-waterbodies-1m (OpenStreetMap-derived; package vintage ~2017). The “1m” label is the upstream Douglas–Peucker simplification tolerance, not a measured shoreline accuracy SLA. Treat results as approximate.
Rebuild locally:
pnpm dataset:buildUses GDAL via Docker when available (FGB_BUILDER=gdal); otherwise falls back to the JS FlatGeobuf serializer (FGB_BUILDER=js). A monthly GitHub Action checks npm for source updates, rebuilds data/, runs the dataset validation suite, and opens a PR when something changed.
© OpenStreetMap contributors. Data licensed under ODbL.
This repo uses Changesets.
- During development, record user-facing changes:
pnpm changeset - On push to
main, GitHub Actions opens (or updates) a Version Packages PR - Merging that PR bumps
package.json, updatesCHANGELOG.md, tags the release, and creates a GitHub Release
CI (typecheck, test, build) runs on every pull request and push to main.
MIT — see LICENSE. Map data remains under OSM/ODbL as noted above.