EveryMap-RS
A modular, type-safe Rust wrapper for geospatial APIs with provider abstraction.
Overview
EveryMap-RS provides a unified interface for geospatial services across multiple providers — HERE Technologies, Google Maps, TomTom, MapBox, and Radar. The architecture uses domain-driven design with 10 geospatial capabilities, each defined as a trait in everymap-core, with provider-specific implementations in separate crates. Switch providers by changing one line of code.
Capabilities covered: geocoding, reverse geocoding, routing / directions, isolines / isochrones, map matching (snap-to-road), tour planning / waypoint optimization (TSP), traffic flow & incidents, map tiles, geodata attributes, and static map images.
Architecture
everymap-rs/
├── everymap-core/ # Core traits, types, auth, error, client
│ └── src/
│ ├── domains/ # 10 domain traits + concrete Options/Response types
│ ├── types/ # Coordinate, BoundingBox, Address, Polyline
│ ├── auth/ # AuthProvider, ApiKeyProvider, HeaderAuthProvider
│ ├── client/ # ProviderClient (shared HTTP logic), HttpClient trait
│ ├── unsupported.rs # 7 stub macros for unsupported domains
│ └── error/ # EveryMapError (structured errors)
├── everymap-providers-here/ # HERE Technologies (10 domains implemented)
├── everymap-providers-google/ # Google Maps (6 domains implemented)
├── everymap-providers-tomtom/ # TomTom (8 domains implemented)
├── everymap-providers-mapbox/ # MapBox (7 domains implemented)
├── everymap-providers-radar/ # Radar (4 domains: search, routing, matching, tour)
├── everymap-cli/ # CLI with 11 commands + unified ProviderRegistry
└── everymap-bench/ # Cross-provider benchmark framework (all 10 domains)
Provider Support
| Domain | Core Trait | HERE | TomTom | MapBox | Radar | |
|---|---|---|---|---|---|---|
| Search | Geocoder |
✅ | ✅ | ✅ | ✅ | ✅ |
| Routing | Router |
✅ | ✅ | ✅ | ✅ | ✅ |
| Isoline | IsolineProvider |
✅ | — | ✅ | ✅ | — |
| Matching | RouteMatcher |
✅ | ✅ | ✅ | ✅ | ✅ |
| Tour | TourPlanner |
✅ | — | ✅ | ✅ | ✅ |
| Traffic | TrafficProvider |
✅ | — | ✅ | — | — |
| Tiling | TileProvider |
✅ | — | ✅ | ✅ | — |
| Positioning | NetworkPositioner |
✅ | ✅ | — | — | — |
| Attributes | AttributeProvider |
✅ | ✅ | — | — | — |
| Imaging | MapImageProvider |
✅ | ✅ | ✅ | ✅ | — |
✅ = real implementation, — = unsupported (stub or N/A). 35 real implementations across 5 providers.
Unsupported domains return a clear UnsupportedDomain error: "google does not support traffic".
Quick Start
Library Usage
use ;
use ;
use ApiKeyProvider;
use Coordinate;
use HereClient;
use HereGeocoder;
use Arc;
async
Switch to Google by changing the provider:
use GoogleClient;
use GoogleGeocoder;
let auth = new;
let client = new;
let geocoder: = Boxnew;
// Same trait, same response types — drop-in replacement
CLI Usage
Important: Global flags (
--provider,--api-key,--output,--verbose) must come before the subcommand. Binary commands (tile,map-image) save to a file instead of printing to stdout. Use--output-fileto set the path.
# HERE provider (default)
# Google provider
# TomTom, MapBox, Radar providers
# Config file (~/.everymap/config.toml)
# [providers.here]
# api_key = "your-here-key"
# [providers.google]
# api_key = "your-google-key"
# Output formats — flag goes before the subcommand
# All 11 commands (examples use HERE provider)
Benchmarking
# Benchmark all domains against all configured providers
# List available domains
# Benchmark a specific domain
# Output formats: table (default), json, markdown
Core Response Types
Enriched types that work across all providers:
Provider-specific methods are available via extension traits (e.g., HereGeocoderExt::discover()) or inherent methods.
Design Principles
- SOLID: Core traits have zero knowledge of provider implementations.
- Type-safe: All API parameters and responses are strongly typed with serde.
- Dynamic dispatch ready: Concrete option types enable
Box<dyn Trait>for runtime provider selection. - TDD: 623 tests (unit + contract + CLI integration + error cases + bench), all passing with nextest.
- Full coverage: All OpenAPI parameters and response fields are modeled.
- Portable: Enriched core types with
rawescape hatch for provider-specific data. - From conversions: All providers implement
From<ProviderType> for CoreType. - Zero duplication: Shared
ProviderClient,unsupported_*!macros, unifiedProviderRegistrydispatch.
Build & Test
See TESTING.md for comprehensive testing guide including live API smoke tests, contract test patterns, and provider-specific API compatibility notes.
Adding a New Provider
- Create
everymap-providers-{name}/withCargo.tomldepending oneverymap-core - Create
client.rs— thin wrapper aroundProviderClientfrom core (copyGoogleClientas template) - Create
domain/geo.rs— shared lat/lng type - Implement supported domain traits (start with
Geocoder+Router) - Add
From<ProviderType> for CoreTypeconversions - Add stubs for unsupported domains using
everymap_core::unsupported_*!macros - Add provider to
ProviderRegistryineverymap-cli/src/provider.rs - Add provider section in
everymap-cli/src/config.rs - Add workspace member in root
Cargo.toml - Add provider to
everymap-bench/src/benchmark.rsBenchProviders::new()
Future Work
- OAuth2 authentication provider
- Upgrade Google routing from legacy Directions API to Routes API v2
- Add
Moderatevariant to coreIncidentSeverity(TomTom traffic) - Configurable image size for the
map-imagecommand - Wire core
avoid/alternativesfields to Radar routing API (currently only viaprovider_extra) - Provider client macro to reduce boilerplate across crates
License
MIT