Skip to content

Repository files navigation

mindat-rs

A Rust client library for the Mindat API.

Crates.io Documentation CI License: MIT

Mindat is the world's largest open database of minerals, rocks, meteorites, and the localities where they come from. This crate provides a type-safe, async interface to access mineralogical data.

Features

  • Full coverage of the Mindat API endpoints
  • Strongly-typed request builders and response models
  • Async/await support using tokio
  • Pagination helpers
  • Comprehensive error handling
  • Optional GUI application built with Tauri (supports desktop and mobile)

Installation

Add this to your Cargo.toml:

[dependencies]
mindat-rs = "0.1"
tokio = { version = "1", features = ["full"] }

Quick Start

use mindat_rs::{MindatClient, GeomaterialsQuery, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // Create a client with your API token
    let client = MindatClient::new("your-api-token");

    // Search for quartz
    let query = GeomaterialsQuery::new()
        .name("quartz")
        .ima_approved(true);

    let minerals = client.geomaterials(query).await?;

    for mineral in minerals.results {
        println!("{}: {:?}", mineral.id, mineral.name);
    }

    Ok(())
}

Authentication

Most API endpoints require authentication with a Mindat API token. You can obtain a token from your Mindat account settings.

Some endpoints (like minerals_ima) can be accessed without authentication:

use mindat_rs::{MindatClient, ImaMineralsQuery};

let client = MindatClient::anonymous();
let minerals = client.minerals_ima(ImaMineralsQuery::new()).await?;

Examples

Search for minerals by element composition

use mindat_rs::{MindatClient, GeomaterialsQuery};

let client = MindatClient::new("your-token");

// Find minerals containing copper and sulfur
let query = GeomaterialsQuery::new()
    .with_elements("Cu,S")
    .ima_approved(true)
    .page_size(50);

let minerals = client.geomaterials(query).await?;

Filter by physical properties

use mindat_rs::{MindatClient, GeomaterialsQuery, CrystalSystem};

let client = MindatClient::new("your-token");

// Find hard, dense minerals in the cubic system
let query = GeomaterialsQuery::new()
    .crystal_systems(vec![CrystalSystem::Isometric])
    .hardness_range(7.0, 10.0)
    .density_range(5.0, 20.0);

let minerals = client.geomaterials(query).await?;

Search localities

use mindat_rs::{MindatClient, LocalitiesQuery};

let client = MindatClient::new("your-token");

// Find gold localities in Brazil
let query = LocalitiesQuery::new()
    .country("Brazil")
    .with_elements("Au");

let localities = client.localities(query).await?;

Find collecting localities near a place

Mindat locality names encode the geographic hierarchy (site → district → county → state → country), so a text filter zeroes in on an area. For example, mines and mineral occurrences in the Tucson Mountains, just west of Tucson, Arizona:

use mindat_rs::{MindatClient, LocalitiesQuery};

let client = MindatClient::new("your-token");

let query = LocalitiesQuery::new()
    .country("USA")
    .name_contains("Tucson Mountains") // Amole Mining District & nearby
    .page_size(8);

let localities = client.localities(query).await?;
for loc in localities.results {
    println!("{}: {}", loc.id, loc.txt.unwrap_or_default());
}

Sample output — copper/lead/silver mines a few miles from downtown, known for wulfenite, vanadinite, chrysocolla, and malachite:

3372: Old Yuma Mine, Tucson Mountain District Saguaro National Park, Amole Mining District, Tucson Mountains, Pima County, Arizona, USA
11361: Gila Monster Mine, Jaynes, Amole Mining District, Tucson Mountains, Pima County, Arizona, USA
20050: Saginaw Hill, Amole Mining District, Tucson Mountains, Pima County, Arizona, USA
21125: Jaynes, Amole Mining District, Tucson Mountains, Pima County, Arizona, USA
34526: Battle Axe Mine, Amole Mining District, Tucson Mountains, Pima County, Arizona, USA

Browse IMA minerals

use mindat_rs::{MindatClient, ImaMineralsQuery};

// IMA list doesn't require authentication
let client = MindatClient::anonymous();

let query = ImaMineralsQuery::new()
    .search("diamond")
    .page_size(10);

let minerals = client.minerals_ima(query).await?;

Pagination

use mindat_rs::{MindatClient, GeomaterialsQuery};

let client = MindatClient::new("your-token");

// Get first page
let query = GeomaterialsQuery::new().page(1).page_size(100);
let page1 = client.geomaterials(query).await?;

println!("Total minerals: {:?}", page1.count);

// Check if there are more pages
if page1.has_next() {
    let query = GeomaterialsQuery::new().page(2).page_size(100);
    let page2 = client.geomaterials(query).await?;
}

Custom client configuration

use mindat_rs::MindatClient;
use std::time::Duration;

let client = MindatClient::builder()
    .token("your-token")
    .timeout(Duration::from_secs(60))
    .build()?;

Available Endpoints

Endpoint Method Description
geomaterials(query) GET Search minerals with filters
geomaterial(id) GET Get a specific geomaterial
geomaterial_varieties(id) GET Get varieties of a geomaterial
geomaterials_search(q, size) GET Quick search for geomaterials
localities(query) GET Search localities with filters
locality(id) GET Get a specific locality
locality_ages(page) / locality_age(id) GET Locality ages
locality_statuses(page) / locality_status(id) GET Locality statuses
locality_types(page) / locality_type(id) GET Locality types
locality_translations(query) / locality_translation(id) GET Locality name translations
minerals_ima(query) GET Full search over IMA-approved minerals (no key)
mineral_ima(id) GET Get a specific IMA mineral
references(query) / reference(id) GET Bibliographic references
reference_authors(..) / reference_authors_unique(page) GET Reference authors
reference_citations(query) / reference_citation(id) GET Reference citations
reference_types / reference_languages / reference_isbn / reference_ddc / reference_lcc / reference_extra / reference_classifications GET Reference lookup tables
occurrences(query) / occurrence(id) GET Mineral-at-locality occurrences
occurrence_statistics(query) / occurrence_statistic(id) GET Aggregated occurrence statistics
loc_by_min(inc, exc) GET Locality IDs by required/excluded minerals
crystal_classes(query) / crystal_class(id) GET Crystal classes (point groups)
space_groups(query) / space_group(id) GET Space groups
space_group_sets(page) / space_group_set(id) GET Space group sets
relations(query) / relation(id) GET Relations between minerals
geoloc_point / geoloc_poly / geomin_point / geomin_poly POST Geospatial point/polygon queries
localities_within(lat, lon, radius_km) All locality IDs within a radius (grids the ~10/point cap)
minerals_within(lat, lon, radius_km) Minerals near a point → the locality IDs that contain them
exports() GET Bulk data export links
dana8_groups() / dana8_subgroups() / dana8(id) GET Dana 8th ed. classification
strunz10_classes() / strunz10_subclasses() / strunz10_families() / strunz10(id) GET Nickel-Strunz 10th ed. classification

Note: The upstream /countries/, /photocount/, and /locgeoregion2/ endpoints were removed from the Mindat v1 API. Filter localities by country with LocalitiesQuery::country("USA") instead of a countries list.

Geospatial radius search: the raw /geoloc-point/ and /geomin-point/ endpoints return only ~10 localities per point regardless of distance. The localities_within and minerals_within helpers probe a hex grid of points across the radius concurrently and merge the results, so you get full coverage from a single call.

Malformed responses: the API occasionally emits unescaped control characters (e.g. raw newlines in free-text fields like description_short) which is invalid JSON. Responses are sanitized before parsing so these records no longer fail.

Error Handling

The library provides detailed error types:

use mindat_rs::{MindatClient, MindatError, GeomaterialsQuery};

let client = MindatClient::new("your-token");
let query = GeomaterialsQuery::new().name("quartz");

match client.geomaterials(query).await {
    Ok(minerals) => println!("Found {} minerals", minerals.results.len()),
    Err(MindatError::AuthenticationRequired) => {
        eprintln!("Invalid or missing API token");
    }
    Err(MindatError::RateLimited) => {
        eprintln!("Too many requests, please wait");
    }
    Err(MindatError::NotFound(msg)) => {
        eprintln!("Resource not found: {}", msg);
    }
    Err(e) => eprintln!("Error: {}", e),
}

GUI Application (Optional)

This crate includes an optional GUI application built with Tauri for testing and exploring the Mindat API. The GUI provides a user-friendly interface to:

  • Search minerals by name, elements, or properties
  • Browse IMA-approved minerals (no authentication required)
  • Explore localities (filter by country name)
  • View classification systems (Dana-8, Strunz-10)
  • Get detailed mineral information

Prerequisites

Linux:

# Ubuntu/Debian
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \
  libssl-dev libayatana-appindicator3-dev librsvg2-dev

# Fedora
sudo dnf install webkit2gtk4.1-devel openssl-devel curl wget file \
  libappindicator-gtk3-devel librsvg2-devel

macOS:

xcode-select --install

Windows:

Building the GUI

# From the repository root
cd gui/src-tauri
cargo build --release

# Or run in development mode
cargo run

Running the GUI

After building, the executable will be at:

  • Linux/macOS: target/release/mindat-gui
  • Windows: target\release\mindat-gui.exe

Using the GUI

  1. Launch the application
  2. Enter your Mindat API token (from mindat.org) and click "Connect"
  3. Use the sidebar to select different API endpoints
  4. The "IMA Minerals" endpoint works without authentication

Mobile Support (iOS/Android)

The GUI is built with Tauri 2.0, which supports mobile platforms. To build for iOS:

# Install Tauri CLI
cargo install tauri-cli

# Initialize iOS (requires Xcode)
cd gui/src-tauri
cargo tauri ios init

# Build for iOS
cargo tauri ios build

For Android:

# Initialize Android (requires Android Studio)
cargo tauri android init

# Build for Android
cargo tauri android build

See the Tauri Mobile Guide for detailed setup instructions.

Related Projects

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

  • Mindat.org for providing the mineralogical database and API
  • The OpenMindat R package for implementation reference

About

A Rust API crate for https://www.mindat.org

Resources

Stars

0 stars

Watchers

1 watching

Forks

Contributors

Languages