qrz-xml

Crates.ioqrz-xml
lib.rsqrz-xml
version0.1.4
created_at2025-05-31 18:40:41.807663+00
updated_at2025-05-31 19:03:56.519781+00
descriptionA Rust client library for the QRZ.com XML API
homepage
repositoryhttps://github.com/n5bur/qrz-xml
max_upload_size
id1696542
size167,083
Luke Burciu (lukeburciu)

documentation

README

qrz-xml

CI

A safe, async Rust client library for the QRZ.com XML API.

Installation

Add this to your Cargo.toml:

[dependencies]
qrz-xml = "0.1"
tokio = { version = "1.0", features = ["full"] }

Example Usage

use qrz_xml::{QrzXmlClient, ApiVersion};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a client using your QRZ.com credentials
    let client = QrzXmlClient::new(
        "your_username", 
        "your_password", 
        ApiVersion::Current
    )?;
    
    // Look up a callsign
    let callsign_info = client.lookup_callsign("AA7BQ").await?;
    println!("Found: {} - {}", 
        callsign_info.call, 
        callsign_info.full_name().unwrap_or_default()
    );
    
    // Look up DXCC entity
    let dxcc_info = client.lookup_dxcc_entity(291).await?;
    println!("DXCC 291: {}", dxcc_info.name);
    
    Ok(())
}

Authentication

You need a valid QRZ.com username and password. While any QRZ user can authenticate, most features require an active QRZ Logbook Data subscription.

Visit QRZ.com subscriptions for more information about subscription plans.

API Coverage

Callsign Lookups

let callsign_info = client.lookup_callsign("W1AW").await?;

// Access comprehensive information
println!("Name: {}", callsign_info.full_name().unwrap_or_default());
println!("Grid: {}", callsign_info.grid.unwrap_or_default());
println!("Country: {}", callsign_info.country.unwrap_or_default());

// Geographic coordinates
if let Some((lat, lon)) = callsign_info.coordinates() {
    println!("Location: {:.4}°, {:.4}°", lat, lon);
}

// QSL preferences
if callsign_info.accepts_eqsl() == Some(true) {
    println!("Accepts eQSL");
}

DXCC Entity Lookups

// Look up by entity number
let usa = client.lookup_dxcc_entity(291).await?;
println!("{} - {}", usa.cc.unwrap(), usa.name);

// Look up by callsign prefix
let dxcc = client.lookup_dxcc_by_callsign("JA1ABC").await?;
println!("Japan: DXCC {}", dxcc.dxcc);

Biography Data

let bio = client.lookup_biography("AA7BQ").await?;
println!("Biography HTML length: {}", bio.html().len());

// The biography contains raw HTML as it appears on QRZ.com
if !bio.is_empty() {
    // Process or display the HTML content
    println!("Has biography data available");
}

Error Handling

The library provides comprehensive error handling with specific error types:

use qrz_xml::QrzXmlError;

match client.lookup_callsign("INVALID").await {
    Ok(info) => println!("Found: {}", info.call),
    Err(QrzXmlError::CallsignNotFound { callsign }) => {
        println!("Callsign {} not found", callsign);
    }
    Err(QrzXmlError::SubscriptionRequired) => {
        println!("This feature requires a QRZ subscription");
    }
    Err(QrzXmlError::AuthenticationFailed { reason }) => {
        println!("Auth failed: {}", reason);
    }
    Err(e) => println!("Other error: {}", e),
}

Configuration

Customize the client behavior with QrzXmlClientConfig:

use qrz::{QrzXmlClient, ApiVersion};
use qrz::client::QrzXmlClientConfig

let config = QrzXmlClientConfig {
    base_url: "https://xmldata.qrz.com/xml".to_string(),
    user_agent: "my-app/1.0".to_string(),
    timeout_seconds: 30,
    max_retries: 3,
};

let client = QrzXmlClient::with_config(
    "username", 
    "password", 
    ApiVersion::Current, 
    config
)?;

API Versions

QRZ.com provides a versioned XML interface. You can specify which version to use:

// Use the latest version (recommended)
let client = QrzXmlClient::new("user", "pass", ApiVersion::Current)?;

// Use a specific version
let client = QrzXmlClient::new("user", "pass", ApiVersion::version("1.34"))?;

// Use legacy version (1.24)
let client = QrzXmlClient::new("user", "pass", ApiVersion::Legacy)?;

Session Management

The client automatically handles session management:

  • Automatic Login: Sessions are established automatically on first request
  • Session Caching: Session keys are cached and reused efficiently
  • Auto Re-authentication: Expired sessions are detected and renewed automatically
  • Session Info: Access lookup counts and subscription status
// Check authentication status
if client.is_authenticated().await {
    println!("Ready to make requests");
}

// Get session information
if let Some((count, sub_exp)) = client.session_info().await {
    println!("Lookups today: {:?}", count);
    println!("Subscription expires: {:?}", sub_exp);
}

// Force re-authentication if needed
client.reauthenticate().await?;

Rate Limiting

The library respects QRZ.com's usage guidelines:

  • Session keys are cached and reused to minimize server load
  • Failed requests are not automatically retried (except for session expiration)
  • The library tracks lookup counts returned by the API

You should implement your own rate limiting if making many requests:

use tokio::time::{sleep, Duration};

for callsign in callsigns {
    let result = client.lookup_callsign(&callsign).await?;
    // Process result...
    
    // Be respectful - add a small delay between requests
    sleep(Duration::from_millis(100)).await;
}

Examples

The crate includes several examples in the examples/ directory:

# Basic callsign lookup
QRZ_USERNAME=xxx QRZ_PASSWORD=yyy cargo run --example basic_lookup -- AA7BQ

# DXCC entity lookup  
QRZ_USERNAME=xxx QRZ_PASSWORD=yyy cargo run --example dxcc_lookup -- --entity 291

Testing

Run the test suite:

cargo test

The tests include both unit tests and integration tests with mocked API responses, so they don't require QRZ.com credentials.

TLS Support

The library supports both native TLS and rustls:

# Use native TLS (default)
qrz_xml = "0.1"

# Use rustls instead
qrz_xml = { version = "0.1", default-features = false, features = ["rustls-tls"] }

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

License

This project is licensed under either of

at your option.

Disclaimer

This library is not affiliated with or endorsed by QRZ.com. QRZ.com is a trademark of QRZ LLC.

Users of this library must comply with QRZ.com's Terms of Service and API usage guidelines.

See Also

Commit count: 23

cargo fmt