A comprehensive API service for finding Canadian electoral district (riding) information using geographic coordinates or addresses. Built on Cloudflare Workers with advanced features including spatial indexing, batch processing, caching, and webhook notifications.
The API provides lookup endpoints for different levels of government:
GET /api— Federal ridings (2024 boundaries)GET /api/qc— Quebec provincial ridings (2025 boundaries)GET /api/on— Ontario provincial ridings (2022 boundaries)
Provide either coordinates or a geocodable address:
latandlon(orlng/long) — Geographic coordinatesaddressorpostal— Street address or postal code (e.g.,H2X 1Y4orM5V 2T6)city— City name (optional, helps with geocoding)stateorprovince— Province/state (optional)country— Country (optional, defaults to Canada)
GET /api?lat=45.5017&lon=-73.5673GET /api/qc?address=350%20Rue%20St-Paul%20E,%20MontréalGET /api/on?postal=M5V2T6GET /api?address=123%20Main%20St&city=Toronto&province=ON
{
"query": { "lat": 45.5017, "lon": -73.5673 },
"point": { "lon": -73.5673, "lat": 45.5017 },
"properties": { /* riding properties from GeoJSON feature, or null */ }
}Process multiple lookups efficiently with automatic geocoding:
POST /batch— Submit batch lookup requestsGET /batch/{batchId}— Check batch processing status
Batch Request Format:
{
"requests": [
{ "id": "req1", "query": { "lat": 45.5017, "lon": -73.5673 } },
{ "id": "req2", "query": { "address": "123 Main St, Toronto, ON" } }
]
}Distributed queue processing with Durable Objects:
POST /api/queue/submit— Submit jobs to processing queueGET /api/queue/status?jobId={id}— Check job statusPOST /api/queue/process— Trigger queue processingGET /api/queue/stats— View queue statistics
Built-in monitoring and observability:
GET /health— Service health check with metrics and circuit breaker statusGET /metrics— Detailed performance metricsGET /cache-warming— Cache warming status and configuration
Optional D1 database backend for improved performance:
POST /api/database/init— Initialize spatial database schemaPOST /api/database/sync— Sync GeoJSON data to databaseGET /api/database/stats— Database statisticsGET /api/database/query— Direct database spatial queries
Access riding boundary data directly:
GET /api/boundaries/lookup— Get boundary geometry for a pointGET /api/boundaries/all— List all boundaries with paginationGET /api/boundaries/config— Spatial indexing configuration
Event-driven notifications for batch completion:
GET /api/webhooks— List configured webhooksPOST /api/webhooks— Create new webhookPUT /api/webhooks/{id}— Update webhook configurationDELETE /api/webhooks/{id}— Remove webhookGET /api/webhooks/events— View webhook event historyGET /api/webhooks/deliveries— View delivery attempts
Interactive API documentation:
GET /— Interactive landing page with API explorerGET /swagger— Swagger UI interfaceGET /api/docs— OpenAPI specification (JSON)
npm i -g wrangler
wrangler loginwrangler r2 bucket create ridingsUpload the boundary datasets with exact keys expected by the worker:
wrangler r2 object put ridings/federalridings-2024.geojson --file ./federalridings-2024.geojson
wrangler r2 object put ridings/quebecridings-2025.geojson --file ./quebecridings-2025.geojson
wrangler r2 object put ridings/ontarioridings-2022.geojson --file ./ontarioridings-2022.geojsonwrangler kv:namespace create "GEOCODING_CACHE"
wrangler kv:namespace create "GEOCODING_CACHE" --previewUpdate the namespace IDs in wrangler.toml.
The QUEUE_MANAGER Durable Object is already configured in wrangler.toml and will be automatically deployed.
wrangler d1 create riding-lookup-dbAdd the database binding to wrangler.toml:
[[d1_databases]]
binding = "RIDING_DB"
database_name = "riding-lookup-db"
database_id = "your-database-id"Primary: GeoGratis (no API key required)
- The service always uses GeoGratis Geolocation API first (https://geogratis.gc.ca/services/geolocation/en/locate)
- No configuration needed, works out of the box
- Automatically falls back to other providers if GeoGratis fails, returns
INTERPOLATED_POSITION, or has poor scoring (< 0.5)
Fallback Providers: The service falls back to the configured provider when GeoGratis is unavailable or returns low-quality results.
Default Fallback: Nominatim (no API key required)
- No configuration needed, works out of the box
Mapbox Geocoding (Fallback):
wrangler secret put MAPBOX_TOKENSet GEOCODER = "mapbox" in wrangler.toml.
Google Maps Geocoding (Fallback):
wrangler secret put GOOGLE_MAPS_KEYSet GEOCODER = "google" in wrangler.toml.
Alternative: Per-request API key
You can pass the Google API key as a header X-Google-API-Key with each request instead of setting the environment variable. This bypasses basic authentication automatically.
Set basic authentication for admin endpoints:
wrangler secret put BASIC_AUTH
# Enter: username:password (will be base64 encoded automatically)Security Note: Authentication Bypass with Google API Key
- If a request includes the
X-Google-API-Keyheader, basic authentication is automatically bypassed - This allows users to use their own Google Maps API key without needing the configured basic auth credentials
- Important: If a Google API key is compromised, the attacker will have full access to the API
- Consider implementing additional rate limiting or access controls per API key if needed
Configure in wrangler.toml under [vars]:
BATCH_SIZE = 50 # Maximum items per batch
BATCH_TIMEOUT = 30000 # Timeout in milliseconds
RATE_LIMIT = 100 # Requests per minute per IPwrangler devThe development environment uses remote R2 storage and KV for full feature testing.
wrangler deployAfter deployment, initialize the D1 spatial database:
curl -X POST https://your-worker.your-subdomain.workers.dev/api/database/init \
-H "Authorization: Basic $(echo -n 'username:password' | base64)"curl -X POST https://your-worker.your-subdomain.workers.dev/api/database/sync \
-H "Authorization: Basic $(echo -n 'username:password' | base64)" \
-H "Content-Type: application/json" \
-d '{"dataset": "federalridings-2024.geojson"}'- Multi-layer caching: LRU caches for GeoJSON data, spatial indexes, and geocoding results
- Automatic cache warming: Background cache warming every 6 hours (currently uses setInterval; consider migrating to Cloudflare Cron Triggers for production)
- Circuit breakers: Automatic failover when external services are unavailable
Note on Cache Warming: The current implementation uses setInterval for cache warming. For production deployments, consider using Cloudflare Cron Triggers by adding to wrangler.toml:
[triggers]
crons = ["0 */6 * * *"] # Every 6 hoursThen handle the scheduled event in the worker's scheduled handler instead of using setInterval.
- Spatial indexing: Bounding box pre-filtering for faster point-in-polygon tests
- D1 integration: Optional database backend with R-tree spatial indexing
- Ray casting algorithm: Supports complex Polygon and MultiPolygon geometries
- IP-based rate limiting: Configurable requests per minute
- Basic authentication: Secure admin endpoints with HTTP Basic Auth
- Input validation: Comprehensive parameter validation and sanitization
The /health endpoint provides comprehensive service status:
- Circuit breaker states for external dependencies
- Cache performance metrics
- Processing latencies and error rates
Built-in metrics tracking:
- Request counts and error rates
- Geocoding performance (cache hits/misses, provider latencies)
- R2 storage performance
- Spatial database query performance
- Batch processing statistics
- Graceful degradation when external services fail
- Detailed error responses with correlation IDs
- Automatic retry with exponential backoff
- Edge computing: Low-latency responses from Cloudflare's global network
- Serverless: Automatic scaling with no infrastructure management
- R2 Storage: Object storage for large GeoJSON boundary files
- KV Storage: Low-latency cache for geocoding results
- Durable Objects: Stateful queue management and coordination
- D1 Database: Optional SQL database with spatial extensions
- Horizontal scaling: Automatic scaling across Cloudflare's edge network
- Memory efficiency: Optimized GeoJSON parsing and spatial indexing
- Batch processing: Efficient handling of bulk lookup requests
- Queue management: Distributed job processing with Durable Objects
- Federal ridings: 2024 electoral boundaries from Elections Canada
- Quebec provincial: 2025 electoral boundaries
- Ontario provincial: 2022 electoral boundaries
- Geocoding: Primary service is GeoGratis Geolocation API (Government of Canada), with fallback to Nominatim, Mapbox, and Google Maps APIs