6 releases (3 breaking)
| new 0.7.0 | Feb 13, 2026 |
|---|---|
| 0.6.1 | Feb 13, 2026 |
| 0.6.0 | Jul 15, 2025 |
| 0.5.1 | Jul 1, 2025 |
| 0.4.0 | Jun 28, 2025 |
#7 in #availability
Used in 2 crates
145KB
2.5K
SLoC
domain-check-lib
A fast, robust Rust library for checking domain availability using RDAP and WHOIS protocols
🚀 Quick Start
Add to your Cargo.toml:
[dependencies]
domain-check-lib = "0.7.0"
tokio = { version = "1", features = ["full"] }
Basic Example:
use domain_check_lib::DomainChecker;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
let result = checker.check_domain("example.com").await?;
match result.available {
Some(true) => println!("{} is AVAILABLE", result.domain),
Some(false) => println!("{} is TAKEN", result.domain),
None => println!("{} status is UNKNOWN", result.domain),
}
Ok(())
}
✨ Key Features
🦀 Pure Async Rust - Built with tokio for high performance
🌐 Dual Protocol Support - RDAP-first with WHOIS fallback
⚡ Concurrent Processing - Check multiple domains simultaneously
🎯 30+ TLD Mappings - Accurate results across major registries
🛡️ Robust Error Handling - Comprehensive error types with recovery
📊 Detailed Information - Extract registrar, dates, and status codes
🔄 Streaming Support - Real-time results for bulk operations
📚 Usage Examples
Single Domain Check
use domain_check_lib::{DomainChecker, CheckConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
let result = checker.check_domain("google.com").await?;
println!("Domain: {}", result.domain);
println!("Available: {:?}", result.available);
println!("Method used: {}", result.method_used);
Ok(())
}
Bulk Domain Checking
use domain_check_lib::{DomainChecker, CheckConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = CheckConfig::default()
.with_concurrency(20)
.with_detailed_info(true);
let checker = DomainChecker::with_config(config);
let domains = vec![
"example.com".to_string(),
"google.org".to_string(),
"github.io".to_string(),
];
let results = checker.check_domains(&domains).await?;
for result in results {
match result.available {
Some(true) => println!("✅ {} is available", result.domain),
Some(false) => println!("❌ {} is taken", result.domain),
None => println!("❓ {} status unknown", result.domain),
}
}
Ok(())
}
Streaming Results (Real-time)
use domain_check_lib::DomainChecker;
use futures::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
let domains = vec![
"example.com".to_string(),
"startup.org".to_string(),
"mybrand.net".to_string(),
];
let mut stream = checker.check_domains_stream(&domains);
while let Some(result) = stream.next().await {
match result {
Ok(domain_result) => {
println!("✓ {}: {:?}", domain_result.domain, domain_result.available);
}
Err(e) => {
eprintln!("✗ Error: {}", e);
}
}
}
Ok(())
}
Custom Configuration
use domain_check_lib::{DomainChecker, CheckConfig};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = CheckConfig::default()
.with_concurrency(50) // Max 50 concurrent checks
.with_timeout(Duration::from_secs(10)) // 10 second timeout
.with_whois_fallback(true) // Enable WHOIS fallback
.with_bootstrap(true) // Use IANA bootstrap
.with_detailed_info(true); // Extract full domain info
let checker = DomainChecker::with_config(config);
let result = checker.check_domain("example.com").await?;
if let Some(duration) = result.check_duration {
println!("Checked in {}ms via {}",
duration.as_millis(),
result.method_used
);
}
Ok(())
}
🆕 TLD Management (v0.5.0)
The library now provides direct access to TLD knowledge for building domain exploration tools:
use domain_check_lib::{get_all_known_tlds, get_preset_tlds, get_available_presets};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get all TLDs with RDAP endpoints
let all_tlds = get_all_known_tlds();
println!("Checking across {} TLDs", all_tlds.len()); // ~42 TLDs
// Use curated presets for common scenarios
let startup_tlds = get_preset_tlds("startup").unwrap();
println!("Startup TLDs: {:?}", startup_tlds); // 8 tech-focused TLDs
// List available presets
let presets = get_available_presets();
println!("Available presets: {:?}", presets); // ["startup", "enterprise", "country"]
Ok(())
}
Smart Domain Expansion
Combine TLD management with domain expansion for powerful bulk operations:
use domain_check_lib::{DomainChecker, get_preset_tlds, expand_domain_inputs};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
// Define base domain names
let base_names = vec!["myapp".to_string(), "mystartup".to_string()];
// Expand with startup-focused TLDs
let startup_tlds = get_preset_tlds("startup");
let domains = expand_domain_inputs(&base_names, &startup_tlds);
// Results in: myapp.com, myapp.io, myapp.ai, etc.
// Check all expanded domains
let results = checker.check_domains(&domains).await?;
// Filter for available domains
let available: Vec<_> = results
.iter()
.filter(|r| r.available == Some(true))
.collect();
println!("Found {} available domains", available.len());
Ok(())
}
🌐 TLD Management: Access to 40+ known TLDs and curated presets
🎯 Smart Expansion: Intelligent domain name expansion with preset integration
📊 Enhanced Results: Improved error context and domain information
Universal TLD Checking
use domain_check_lib::{DomainChecker, get_all_known_tlds};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
// Check against all known TLDs
let all_tlds = get_all_known_tlds();
let domains = domain_check_lib::expand_domain_inputs(
&["myapp".to_string()],
&Some(all_tlds)
);
println!("Checking {} domains across all TLDs", domains.len());
let results = checker.check_domains(&domains).await?;
// Analyze results
let available_count = results.iter().filter(|r| r.available == Some(true)).count();
let taken_count = results.iter().filter(|r| r.available == Some(false)).count();
println!("Results: {} available, {} taken", available_count, taken_count);
Ok(())
}
File-based Processing
use domain_check_lib::DomainChecker;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let checker = DomainChecker::new();
// Process domains from a file (one domain per line)
let results = checker.check_domains_from_file("domains.txt").await?;
let available_domains: Vec<_> = results
.iter()
.filter(|r| r.available == Some(true))
.collect();
println!("Found {} available domains out of {}",
available_domains.len(),
results.len()
);
for domain in available_domains {
println!("✅ {}", domain.domain);
}
Ok(())
}
🔧 Configuration Options
The CheckConfig struct provides extensive configuration:
use domain_check_lib::CheckConfig;
use std::time::Duration;
let config = CheckConfig::default()
.with_concurrency(25) // Concurrent requests (1-100)
.with_timeout(Duration::from_secs(8)) // Per-domain timeout
.with_whois_fallback(true) // Enable WHOIS fallback
.with_bootstrap(false) // IANA bootstrap lookup
.with_detailed_info(true) // Extract registrar details
.with_tlds(vec![ // Default TLDs for expansion
"com".to_string(),
"org".to_string(),
"net".to_string()
]);
📊 Data Structures
DomainResult
pub struct DomainResult {
pub domain: String, // Domain that was checked
pub available: Option<bool>, // true = available, false = taken, None = unknown
pub info: Option<DomainInfo>, // Detailed registration info (if available)
pub check_duration: Option<Duration>, // How long the check took
pub method_used: CheckMethod, // RDAP, WHOIS, or Bootstrap
pub error_message: Option<String>, // Error details (if applicable)
}
DomainInfo
pub struct DomainInfo {
pub registrar: Option<String>, // Domain registrar
pub creation_date: Option<String>, // When domain was registered
pub expiration_date: Option<String>, // When domain expires
pub status: Vec<String>, // Domain status codes
pub updated_date: Option<String>, // Last update date
pub nameservers: Vec<String>, // Associated nameservers
}
🌐 Protocol Support
RDAP (Primary)
- Modern Protocol: Structured JSON responses
- 30+ TLD Mappings: Major registries supported
- Rich Data: Registrar info, dates, status codes
- Performance: Fast, reliable responses
WHOIS (Fallback)
- Universal Coverage: Works with most TLDs
- Automatic Parsing: Intelligent response interpretation
- Rate Limiting: Built-in throttling protection
- Error Recovery: Smart fallback logic
Bootstrap Discovery
- IANA Registry: Dynamic endpoint discovery
- Unknown TLDs: Automatic protocol detection
- Future Proof: Adapts to new registries
🚀 Performance
Domain Check is optimized for high-performance operations:
- Concurrent Processing: Configurable parallelism (1-100 concurrent requests)
- Connection Reuse: HTTP client connection pooling
- Smart Timeouts: Registry-specific timeout optimization
- Memory Efficient: Streaming results for large datasets
- Protocol Selection: Intelligent RDAP/WHOIS routing
🛡️ Error Handling
Comprehensive error types with automatic recovery:
use domain_check_lib::DomainCheckError;
match checker.check_domain("invalid-domain").await {
Ok(result) => println!("Success: {:?}", result),
Err(DomainCheckError::InvalidDomain { domain, reason }) => {
eprintln!("Invalid domain '{}': {}", domain, reason);
}
Err(DomainCheckError::NetworkError { message, .. }) => {
eprintln!("Network error: {}", message);
}
Err(DomainCheckError::Timeout { operation, duration }) => {
eprintln!("Timeout after {:?}: {}", duration, operation);
}
Err(e) => eprintln!("Other error: {}", e),
}
🔗 Related Projects
- CLI Tool:
domain-check- Command-line interface - Repository: GitHub - Source code and issues
📝 License
This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please see the Contributing Guide for details.
Built with ❤️ in Rust
Dependencies
~9–27MB
~327K SLoC