ipdatainfo 0.1.0

Official Rust client for the ipdata.info IP geolocation, ASN, and threat-intelligence API
Documentation
mod support;

use ipdatainfo::{Client, Error, PRO_BASE_URL};

#[test]
fn lookup_parses_response() {
    let body = r#"{"ip":"8.8.8.8","success":true,"type":"IPv4",
        "country":"United States","country_code":"US","asn":15169,
        "security":{"tor":false,"proxy":false}}"#;
    let (base_url, rx) = support::spawn("HTTP/1.1 200 OK", body);

    let client = Client::builder().base_url(base_url).build();
    let info = client.lookup("8.8.8.8").expect("lookup should succeed");

    assert_eq!(info.country_code.as_deref(), Some("US"));
    assert_eq!(info.asn, Some(15169));
    assert!(info.security.is_some());

    let captured = rx.recv().expect("server should capture a request");
    assert!(captured.request_line.starts_with("GET /json/8.8.8.8"));
    assert!(!captured.had_api_key_header);
}

#[test]
fn error_response_is_parsed_into_api_error() {
    let (base_url, _rx) = support::spawn(
        "HTTP/1.1 403 Forbidden",
        r#"{"error":"batch lookup requires a paid tier API key"}"#,
    );

    let client = Client::builder().base_url(base_url).build();
    let err = client.batch(&["8.8.8.8"]).expect_err("batch should fail");

    match err {
        Error::Api { status, message } => {
            assert_eq!(status, 403);
            assert_eq!(message, "batch lookup requires a paid tier API key");
        }
        other => panic!("expected Error::Api, got {other:?}"),
    }
}

#[test]
fn api_key_switches_to_pro_host_and_is_sent_as_header() {
    let (base_url, rx) = support::spawn("HTTP/1.1 200 OK", r#"{"ip":"8.8.8.8"}"#);

    // Default base URL (no explicit override) should target the pro host once
    // an API key is set.
    let default_client = Client::builder().api_key("secret").build();
    assert_eq!(default_client.base_url(), PRO_BASE_URL);

    // With an explicit base URL (our mock server), the key should still be
    // sent as the X-Api-Key header.
    let client = Client::builder()
        .api_key("secret")
        .base_url(base_url)
        .build();
    let _ = client.lookup("8.8.8.8").expect("lookup should succeed");

    let captured = rx.recv().expect("server should capture a request");
    assert!(captured.had_api_key_header);
}