| Crates.io | arcgis |
| lib.rs | arcgis |
| version | 0.1.0 |
| created_at | 2026-01-26 01:34:56.872456+00 |
| updated_at | 2026-01-26 01:34:56.872456+00 |
| description | Type-safe Rust SDK for the ArcGIS REST API with compile-time guarantees |
| homepage | https://github.com/crumplecup/arcgis |
| repository | https://github.com/crumplecup/arcgis |
| max_upload_size | |
| id | 2070004 |
| size | 1,380,192 |
A type-safe Rust SDK for the ArcGIS REST API with compile-time guarantees.
Current Status: 113 operations across 12 services (65% API coverage, 80% use case coverage)
geo-types and the GeoRust ecosystemtokio and reqwest for async operationsFeature Management (Feature Service):
Mapping (Map Service):
Geocoding (Geocode Service):
Geometry Operations (Geometry Service):
Network Analysis (Routing Service):
Geoprocessing:
Portal & Content Management:
Imagery (Image Service):
3D & Tiles:
Versioned Workflows (Version Management):
Location Services:
Add to your Cargo.toml:
[dependencies]
arcgis = "0.1"
tokio = { version = "1", features = ["full"] }
Create a .env file in your project root (automatically loaded by the SDK):
cp .env.example .env
Add your credentials to .env:
ARCGIS_API_KEY=your_api_key_here
Important: Add .env to your .gitignore to keep credentials out of version control!
Get your API key from the ArcGIS Developer Dashboard.
use arcgis::{ApiKeyAuth, ArcGISClient, FeatureServiceClient, LayerId};
#[tokio::main]
async fn main() -> arcgis::Result<()> {
// Load API key from environment (.env is automatically loaded)
let api_key = std::env::var("ARCGIS_API_KEY")
.expect("ARCGIS_API_KEY must be set in .env");
// Create authenticated client
let auth = ApiKeyAuth::new(api_key);
let client = ArcGISClient::new(auth);
// Connect to a feature service
let service = FeatureServiceClient::new(
"https://services.arcgis.com/org/arcgis/rest/services/Dataset/FeatureServer",
&client,
);
// Query features with type-safe builder API
let features = service
.query(LayerId::new(0))
.where_clause("POPULATION > 100000")
.out_fields(&["NAME", "POPULATION", "STATE"])
.return_geometry(true)
.execute()
.await?;
println!("Retrieved {} features", features.features().len());
// Geometries are returned as geo-types
for feature in features.features() {
if let Some(geometry) = feature.geometry() {
println!("Feature geometry: {:?}", geometry);
}
}
Ok(())
}
For large datasets, use execute_all() to automatically paginate:
// Retrieve all features matching the query (may make multiple requests)
let all_features = service
.query(LayerId::new(0))
.where_clause("STATE = 'CA'")
.execute_all() // Automatically handles pagination
.await?;
println!("Retrieved {} total features", all_features.features().len());
Instead of error-prone strings:
// โ Runtime errors waiting to happen
params.geometry_type = "esriGeometryPolyline"; // Typo? No compile error!
params.spatial_rel = "esriSpatialRelIntersect"; // Missing 's'? No compile error!
Use strongly-typed enums:
// โ
Compile-time guarantees
use arcgis::{GeometryType, SpatialRel};
params.geometry_type = GeometryType::Polyline; // Autocomplete works!
params.spatial_rel = SpatialRel::Intersects; // Typos = compile errors!
The SDK automatically loads credentials from a .env file when you create a client. This keeps your API keys and secrets out of your code and version control.
Best for development, testing, and simple applications:
use arcgis::{ApiKeyAuth, ArcGISClient};
// Load API key from environment (.env automatically loaded)
let api_key = std::env::var("ARCGIS_API_KEY")
.expect("ARCGIS_API_KEY must be set in .env");
let auth = ApiKeyAuth::new(api_key);
let client = ArcGISClient::new(auth);
Fully automated server-to-server authentication - no browser or user interaction required:
use arcgis::{ClientCredentialsAuth, ArcGISClient, AuthProvider};
#[tokio::main]
async fn main() -> arcgis::Result<()> {
// Create authenticator with client credentials
let auth = ClientCredentialsAuth::new(
std::env::var("ARCGIS_CLIENT_ID")?,
std::env::var("ARCGIS_CLIENT_SECRET")?,
)?;
// Token is fetched automatically on first use
let client = ArcGISClient::new(auth);
// All subsequent requests automatically use refreshed tokens
// No manual token management required!
Ok(())
}
Key features:
See examples/client_credentials_flow.rs for a complete example.
See the examples/ directory for complete examples:
basic_client.rs - Basic client setup and usageclient_credentials_flow.rs - OAuth 2.0 automated authenticationRun an example:
cargo run --example client_credentials_flow
Run unit tests (no credentials required):
cargo test
Integration tests require ArcGIS credentials and the api feature flag.
Set up credentials:
cp .env.example .env
# Edit .env and add your ARCGIS_API_KEY or ARCGIS_CLIENT_ID/ARCGIS_CLIENT_SECRET
Run integration tests:
# Run all API tests (be patient, includes rate limiting)
cargo test --features api
# Or use the justfile recipe
just test-api
# Run specific test
cargo test --features api test_public_feature_service_accessible
See tests/README.md for more details.
All geometries use the GeoRust ecosystem via geo-types. ArcGIS geometries are automatically converted when querying features:
use geo_types::{Point, Polygon};
// Query features - geometries are returned as geo-types
let features = service
.query(LayerId::new(0))
.return_geometry(true)
.execute()
.await?;
// Work with native geo-types
for feature in features.features() {
if let Some(geometry) = feature.geometry() {
match geometry {
geo_types::Geometry::Point(pt) => println!("Point at {}, {}", pt.x(), pt.y()),
geo_types::Geometry::Polygon(poly) => println!("Polygon with {} points", poly.exterior().points().count()),
_ => {}
}
}
}
This SDK prioritizes type safety and correctness:
LayerId, ObjectId) to prevent mixingoauth2, GeoRust, reqwest, and tokio instead of reinventingSee ARCGIS_REST_API_RESEARCH.md for the full design rationale.
This crate requires Rust 1.75 or later.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
# Clone the repository
git clone https://github.com/crumplecup/arcgis.git
cd arcgis
# Build the project
cargo build
# Run tests
cargo test
# Run tests with all features
cargo test --all-features
# Check formatting
cargo fmt --check
# Run clippy
cargo clippy --all-targets --all-features
12 Services, 113 Operations (Baseline - 65% coverage):
| Service | Operations | Status |
|---|---|---|
| Elevation | 3 | โ Complete |
| Feature | 17 | โ Complete (queries, edits, attachments, admin) |
| Geocode | 9 | โ Complete (forward, reverse, batch, suggest) |
| Geometry | 8 | โ Core Complete (project, buffer, union, measure) |
| Geoprocessing | 7 | โ Complete (sync/async execution, polling) |
| Image | 6 | โ Core Complete (export, identify, samples, histograms) |
| Map | 10 | โ Complete (export, legend, identify, KML, renderer) |
| Places | 3 | โ Complete (search, details, categories) |
| Portal | 24 | โ Core Complete (users, items, sharing, publishing, groups) |
| Routing | 4 | โ Complete (route, service area, closest facility, OD matrix) |
| Vector Tile | 6 | โ Core Complete (tiles, style, fonts, sprites) |
| Version Management | 16 | โ Complete (sessions, CRUD, reconcile, conflicts) |
See COVERAGE_ROADMAP.md for the path to full coverage.
Bronze (Phase 1 - 70% coverage):
Silver (Phase 2 - 75% coverage):
Gold (Phase 3 - 80% coverage):
Platinum (Full Coverage - 80-85% coverage):
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
This is an unofficial community-driven project and is not officially supported by Esri. For official Esri SDKs, see ArcGIS Developer Documentation.