ipwhois-rust 1.2.0

Official Rust client for the ipwhois.io IP Geolocation API. Simple, supports single and bulk IP lookups.
Documentation
//! End-to-end test of the bulk-response decode path. We don't hit the real
//! API β€” we feed a sample JSON payload through the public response type and
//! check it round-trips cleanly. Real HTTP behaviour is covered by the
//! unit tests in `src/client.rs`.

use ipwhois::LookupResponse;

#[test]
fn bulk_payload_round_trips() {
    let json = r#"[
        {
            "ip": "8.8.8.8",
            "success": true,
            "type": "IPv4",
            "country": "United States",
            "country_code": "US",
            "city": "Mountain View",
            "flag": {
                "img": "https://cdn.ipwhois.io/flags/us.svg",
                "emoji": "πŸ‡ΊπŸ‡Έ",
                "emoji_unicode": "U+1F1FA U+1F1F8"
            },
            "connection": { "asn": 15169, "isp": "Google LLC" }
        },
        {
            "success": false,
            "ip": "999.999.999.999",
            "message": "Invalid IP address",
            "error_type": "api"
        }
    ]"#;

    let parsed: Vec<LookupResponse> = serde_json::from_str(json).expect("parse");
    assert_eq!(parsed.len(), 2);

    let ok = &parsed[0];
    assert!(ok.success);
    assert_eq!(ok.ip.as_deref(), Some("8.8.8.8"));
    assert_eq!(ok.country_code.as_deref(), Some("US"));
    assert_eq!(
        ok.flag.as_ref().and_then(|f| f.emoji.as_deref()),
        Some("πŸ‡ΊπŸ‡Έ")
    );
    assert_eq!(
        ok.connection.as_ref().and_then(|c| c.isp.as_deref()),
        Some("Google LLC")
    );

    let bad = &parsed[1];
    assert!(!bad.success);
    assert_eq!(bad.message.as_deref(), Some("Invalid IP address"));
    assert_eq!(bad.error_type.as_deref(), Some("api"));
}

#[test]
fn extra_fields_land_in_the_extra_map() {
    // Forward-compatibility: a future server-side field shouldn't break
    // deserialisation.
    let json = r#"{
        "ip": "8.8.8.8",
        "success": true,
        "country": "United States",
        "future_field_we_dont_know_about": { "answer": 42 }
    }"#;

    let parsed: LookupResponse = serde_json::from_str(json).expect("parse");
    assert!(parsed.success);
    assert!(parsed.extra.contains_key("future_field_we_dont_know_about"));
}