| Crates.io | leetify |
| lib.rs | leetify |
| version | 0.1.1 |
| created_at | 2025-12-07 21:51:04.084928+00 |
| updated_at | 2025-12-07 22:21:25.142221+00 |
| description | A Rust client library for the Leetify Public CS API |
| homepage | https://github.com/muijf/leetify |
| repository | https://github.com/muijf/leetify |
| max_upload_size | |
| id | 1972316 |
| size | 232,223 |

A Rust client library for the Leetify Public CS API
Type-safe, async API client with comprehensive error handling, builder pattern configuration, and an ergonomic extended Player API.
Key Features: Type-safe IDs • Builder pattern • Extended Player API • Comprehensive error handling • Full async/await support • Automatic JSON deserialization • API key validation • Feature flags for customization
Add this to your Cargo.toml:
[dependencies]
leetify = "0.1.1"
tokio = { version = "1", features = ["full"] }
Note: This library requires an async runtime. Tokio is recommended, but any async runtime compatible with
reqwestwill work.
Most features are optional to keep the core library lightweight. Enable only what you need.
Core Features:
default - Enables all default features (player, rustls-tls)player - Enables the extended Player API for a more ergonomic interfacerustls-tls - Uses rustls as the TLS backend for reqwest (default, recommended)native-tls - Uses native-tls as the TLS backend for reqwestQuick examples:
# Default (includes player API and rustls)
leetify = "0.1.1"
# Minimal setup (without Player API)
leetify = { version = "0.1.1", default-features = false, features = ["rustls-tls"] }
# With native-tls instead of rustls
leetify = { version = "0.1.1", default-features = false, features = ["player", "native-tls"] }
# Custom feature combination
leetify = { version = "0.1.1", default-features = false, features = ["player", "rustls-tls"] }
Note: The
playerfeature enables the extendedPlayerAPI which provides a more ergonomic interface. The coreClientAPI is always available.
use leetify::{Client, Id};
#[tokio::main]
async fn main() -> Result<(), leetify::Error> {
// Create a client
let client = Client::new();
// Get player profile by Steam64 ID
let profile = client
.get_profile(Id::Steam64("76561198283431555".into()))
.await?;
println!("Player: {}", profile.name);
println!("Winrate: {:.2}%", profile.winrate * 100.0);
Ok(())
}
Output:
Player: PlayerName
Winrate: 52.34%
For more examples and usage patterns, see the examples.
use leetify::{Client, Id};
let client = Client::new();
// By Steam64 ID
let profile = client
.get_profile(Id::Steam64("76561198283431555".into()))
.await?;
// By Leetify ID (UUID format)
let profile = client
.get_profile(Id::Leetify("5ea07280-2399-4c7e-88ab-f2f7db0c449f".into()))
.await?;
// Using automatic conversion (UUID format -> Leetify, numeric strings -> Steam64)
let id: Id = "76561198283431555".into();
let profile = client.get_profile(id).await?;
use leetify::{Client, Id};
let client = Client::new();
let matches = client
.get_profile_matches(Id::Steam64("76561198283431555".into()))
.await?;
for match_details in matches {
println!("Match: {} on {}", match_details.id, match_details.map_name);
}
use leetify::{Client, DataSource};
let client = Client::new();
// By game ID
let match_details = client
.get_match_by_game_id("match-id-123".to_string())
.await?;
// By data source
let match_details = client
.get_match_by_data_source(DataSource::FACEIT, "faceit-match-id")
.await?;
use leetify::Client;
let client = Client::with_api_key("your-api-key".to_string());
match client.validate_api_key().await {
Ok(()) => println!("API key is valid"),
Err(e) => eprintln!("Validation failed: {}", e),
}
API keys provide higher rate limits. You can obtain one at https://leetify.com/app/developer.
use leetify::Client;
let client = Client::with_api_key("your-api-key".to_string());
For advanced configuration:
use leetify::Client;
use std::time::Duration;
let client = Client::builder()
.api_key("your-api-key")
.timeout(Duration::from_secs(60))
.base_url("https://custom-api.example.com")
.build()?;
The extended
PlayerAPI provides a more ergonomic interface by storing the player ID, allowing you to call methods without passing it each time. Enable theplayerfeature to use this API.
For a more ergonomic API, use the Player struct which stores the id
and allows you to call methods without passing it each time:
use leetify::{Client, Id};
let client = Client::new();
let player = client.player(Id::Steam64("76561198283431555".into()));
// Get profile
let profile = player.profile().await?;
// Get matches
let matches = player.matches().await?;
The library provides type-safe wrappers to prevent mixing up different ID types:
Id - Enum for player identification (either Steam64 or Leetify)Steam64Id - For Steam 64-bit IDs (numeric strings, typically 17 digits)LeetifyId - For Leetify user IDs (UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)DataSource - Enum for data sources (FACEIT, Matchmaking, etc.)The Id enum can be created from strings with automatic detection:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are treated as Leetify IDsId::Steam64 or Id::Leetify) for clarityThe library provides comprehensive error types:
use leetify::Error;
match result {
Ok(data) => println!("Success: {:?}", data),
Err(Error::MissingParameter(msg)) => eprintln!("Missing required parameter: {}", msg),
Err(Error::InvalidApiKey) => eprintln!("Invalid API key"),
Err(Error::Http(e)) => eprintln!("HTTP error: {}", e),
Err(Error::Api(status, msg)) => eprintln!("API error {}: {}", status, msg),
Err(e) => eprintln!("Other error: {}", e),
}
Run any example with:
cargo run --example <name>
Core Examples:
basic_usage - Basic API usage with all methodsplayer_api - Extended Player API usageuse leetify::{Client, Id, DataSource};
#[tokio::main]
async fn main() -> Result<(), leetify::Error> {
let client = Client::new();
// Get profile
let profile = client
.get_profile(Id::Steam64("76561198283431555".into()))
.await?;
// Get matches
let matches = client
.get_profile_matches(Id::Steam64("76561198283431555".into()))
.await?;
// Get match details
let match_details = client
.get_match_by_data_source(DataSource::FACEIT, "faceit-match-id")
.await?;
Ok(())
}
use leetify::{Client, Id};
#[tokio::main]
async fn main() -> Result<(), leetify::Error> {
let client = Client::new();
let player = client.player(Id::Steam64("76561198283431555".into()));
// No need to pass ID each time
let profile = player.profile().await?;
let matches = player.matches().await?;
Ok(())
}
Format code:
cargo fmt --all
Formats all Rust code according to the official style guide.
Lint code:
cargo clippy --all-targets --all-features -- -D warnings
Runs Clippy linter with all targets and features enabled, treating warnings as errors.
Run tests:
cargo test --all-features
Runs all tests with all features enabled to ensure comprehensive coverage.
Run doc tests:
cargo test --doc
Runs documentation tests to ensure all code examples compile and work correctly.
Editor setup: Recommended extensions are available in
.vscode/extensions.json. See CONTRIBUTING.md for development guidelines and pre-commit hooks.
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.