ipdata 0.1.1

Official Rust client for the ipdata.co IP geolocation and threat intelligence API
Documentation
# ipdata

Rust client for the [ipdata.co](https://ipdata.co) IP geolocation and threat intelligence API.

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
ipdata = "0.1"
```

## Usage

### Single IP Lookup

```rust
let client = ipdata::IpData::new("your-api-key");
let info = client.lookup("8.8.8.8").await?;
println!("{} is in {}", info.ip, info.country_name.unwrap_or_default());
```

### Look Up Your Own IP

```rust
let info = client.lookup_self().await?;
```

### Field Filtering

Request only specific fields to reduce response size:

```rust
let info = client.lookup_fields("8.8.8.8", &["ip", "country_name", "asn"]).await?;
```

### Single Field Lookup

```rust
let asn = client.lookup_field("8.8.8.8", "asn").await?;
```

### Bulk Lookup

Look up to 100 IPs in a single request (requires a paid API key):

```rust
let results = client.bulk(&["8.8.8.8", "1.1.1.1"]).await?;
for info in &results {
    println!("{} -> {}", info.ip, info.country_name.as_deref().unwrap_or("unknown"));
}
```

### Typed Sub-resource Lookups

Get specific data with strongly-typed return values:

```rust
let asn = client.asn("8.8.8.8").await?;
println!("ASN: {} ({})", asn.asn, asn.name);

let threat = client.threat("8.8.8.8").await?;
println!("Is threat: {}", threat.is_threat);

let tz = client.time_zone("8.8.8.8").await?;
println!("Timezone: {}", tz.name);

let currency = client.currency("8.8.8.8").await?;
println!("Currency: {} ({})", currency.name, currency.code);

let carrier = client.carrier("8.8.8.8").await?;
println!("Carrier: {}", carrier.name);
```

### EU Endpoint

Use the EU-specific endpoint backed by datacenters in Frankfurt, Paris, and Ireland:

```rust
let client = ipdata::IpData::eu("your-api-key");
```

### Custom Endpoint

```rust
let client = ipdata::IpData::with_base_url("your-api-key", "https://custom-endpoint.example.com");
```

## Error Handling

```rust
match client.lookup("8.8.8.8").await {
    Ok(info) => println!("{}", info.ip),
    Err(ipdata::Error::Api { status, message }) => {
        eprintln!("API error ({}): {}", status, message);
    }
    Err(ipdata::Error::InvalidIp(ip)) => {
        eprintln!("Bad IP: {}", ip);
    }
    Err(e) => eprintln!("Error: {}", e),
}
```

## Response Types

The main response type is `IpInfo` which includes:

- **Geolocation**: `city`, `region`, `country_name`, `country_code`, `continent_name`, `latitude`, `longitude`, `postal`
- **ASN**: `asn` (struct with `asn`, `name`, `domain`, `route`, `asn_type`)
- **Company**: `company` (struct with `name`, `domain`, `network`, `company_type`)
- **Carrier**: `carrier` (struct with `name`, `mcc`, `mnc`)
- **Currency**: `currency` (struct with `name`, `code`, `symbol`, `native`, `plural`)
- **Time Zone**: `time_zone` (struct with `name`, `abbreviation`, `offset`, `is_dst`, `current_time`)
- **Organisation**: `organisation` (ISP / organization name)
- **Threat**: `threat` (struct with `is_tor`, `is_vpn`, `is_proxy`, `is_anonymous`, `is_threat`, `is_bogon`, `blocklists`, `scores`, and more)
- **Languages**: `languages` (vec of `Language` with `name`, `native`, `code`)

## License

MIT