Skip to content

Commit 479a833

Browse files
authored
Add IpInfoLite to support Lite API (#64)
* Fix failing tests * Add support for Lite API * Fix clippy issues
1 parent 77b32a5 commit 479a833

File tree

8 files changed

+552
-15
lines changed

8 files changed

+552
-15
lines changed

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ The free plan is limited to 50,000 requests per month, and doesn't include some
2828
data fields such as the IP type and company information. To get the complete list of
2929
information on an IP address and make more requests per day see [https://ipinfo.io/pricing](https://ipinfo.io/pricing).
3030

31-
⚠️ Note: This library does not currently support our newest free API https://ipinfo.io/lite. If you’d like to use IPinfo Lite, you can call the [endpoint directly](https://ipinfo.io/developers/lite-api) using your preferred HTTP client. Developers are also welcome to contribute support for Lite by submitting a pull request.
31+
The library also supports the Lite API, see the [Lite API section](#lite-api) for more info.
3232

3333
## Examples
3434

@@ -110,6 +110,42 @@ let config = IpInfoConfig {
110110
};
111111
```
112112

113+
### Lite API
114+
115+
The library gives the possibility to use the [Lite API](https://ipinfo.io/developers/lite-api) too, authentication with your token is still required.
116+
117+
The returned details are slightly different from the Core API.
118+
119+
There's a Lite API example too in the `/examples` directory. You can run it directly like the others, remember to replace `<token>` with your access token
120+
121+
```bash
122+
cargo run --example lookup_lite -- <token>
123+
```
124+
125+
The `lookup_lite` example above looks more or less like
126+
127+
```rust
128+
use ipinfo::{IpInfoLite, IpInfoLiteConfig};
129+
#[tokio::main]
130+
async fn main() {
131+
let config = IpInfoLiteConfig {
132+
token: Some("<token>".to_string()),
133+
..Default::default()
134+
};
135+
136+
let mut ipinfo = IpInfoLite::new(config)
137+
.expect("should construct");
138+
139+
let res = ipinfo.lookup_self_v4().await;
140+
match res {
141+
Ok(r) => {
142+
println!("Current IP lookup result: {:?}", r);
143+
},
144+
Err(e) => println!("error occurred: {}", &e.to_string()),
145+
}
146+
}
147+
```
148+
113149
## Other Libraries
114150

115151
There are official IPinfo client libraries available for many languages including

examples/lookup_lite.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use ipinfo::{IpInfoLite, IpInfoLiteConfig};
2+
use std::env;
3+
4+
#[tokio::main]
5+
async fn main() {
6+
let token = env::args().nth(1);
7+
8+
let config = IpInfoLiteConfig {
9+
token,
10+
..Default::default()
11+
};
12+
13+
let mut ipinfo = IpInfoLite::new(config).expect("should construct");
14+
15+
let res = ipinfo.lookup_self_v4().await;
16+
match res {
17+
Ok(r) => {
18+
println!("Current IP lookup result: {:?}", r);
19+
}
20+
Err(e) => println!("error occurred: {}", &e.to_string()),
21+
}
22+
}

src/api.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,72 @@ pub struct DomainsDetails {
197197
}
198198

199199
/// CountryFlag details.
200-
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
200+
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
201201
pub struct CountryFlag {
202202
pub emoji: String,
203203
pub unicode: String,
204204
}
205205

206206
/// CountryCurrency details.
207-
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
207+
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
208208
pub struct CountryCurrency {
209209
pub code: String,
210210
pub symbol: String,
211211
}
212212

213213
/// Continent details.
214-
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
214+
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
215215
pub struct Continent {
216216
pub code: String,
217217
pub name: String,
218218
}
219+
220+
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
221+
pub struct IpDetailsLite {
222+
pub ip: String,
223+
224+
/// The country code for the IP address.
225+
pub country_code: String,
226+
227+
/// The country name for the IP address.
228+
pub country: String,
229+
230+
/// The country name for the IP address.
231+
#[serde(skip_deserializing)]
232+
pub country_name: String,
233+
234+
/// EU status of the country.
235+
#[serde(skip_deserializing)]
236+
pub is_eu: bool,
237+
238+
/// Flag and unicode of the country.
239+
#[serde(skip_deserializing)]
240+
pub country_flag: CountryFlag,
241+
242+
/// Link of the Flag of country.
243+
#[serde(skip_deserializing)]
244+
pub country_flag_url: String,
245+
246+
/// Code and symbol of the country's currency.
247+
#[serde(skip_deserializing)]
248+
pub country_currency: CountryCurrency,
249+
250+
/// The AS number.
251+
pub asn: String,
252+
253+
/// The AS name.
254+
pub as_name: String,
255+
256+
/// The AS domain.
257+
pub as_domain: String,
258+
259+
/// Code and name of the continent.
260+
#[serde(skip_deserializing)]
261+
pub continent: Continent,
262+
263+
/// If the IP Address is Bogon
264+
pub bogon: Option<bool>,
265+
266+
#[serde(flatten)]
267+
pub extra: HashMap<String, Value>,
268+
}

src/bogon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ lazy_static! {
118118
/// assert_eq!(is_bogon("foo"), false);
119119
/// ```
120120
pub fn is_bogon(ip_address: &str) -> bool {
121-
ip_address.parse().map_or(false, is_bogon_addr)
121+
ip_address.parse().is_ok_and(is_bogon_addr)
122122
}
123123

124124
/// Returns a boolean indicating whether an IP address is bogus.

src/ipinfo.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ impl IpInfo {
260260
) -> Result<HashMap<String, IpDetails>, IpError> {
261261
// Lookup cache misses which are not bogon
262262
let response = client
263-
.post(format!("{}/batch", BASE_URL))
263+
.post(format!("{BASE_URL}/batch"))
264264
.headers(Self::construct_headers())
265265
.bearer_auth(self.token.as_deref().unwrap_or_default())
266266
.json(&json!(ips))
@@ -363,7 +363,7 @@ impl IpInfo {
363363
// lookup in case of a cache miss
364364
let response = self
365365
.client
366-
.get(format!("{}/{}", base_url, ip))
366+
.get(format!("{base_url}/{ip}"))
367367
.headers(Self::construct_headers())
368368
.bearer_auth(self.token.as_deref().unwrap_or_default())
369369
.send()
@@ -412,7 +412,7 @@ impl IpInfo {
412412
return Err(err!(MapLimitError));
413413
}
414414

415-
let map_url = &format!("{}/tools/map?cli=1", BASE_URL);
415+
let map_url = &format!("{BASE_URL}/tools/map?cli=1");
416416
let client = self.client.clone();
417417
let json_ips = serde_json::json!(ips);
418418

@@ -454,7 +454,7 @@ impl IpInfo {
454454
let mut headers = HeaderMap::new();
455455
headers.insert(
456456
USER_AGENT,
457-
HeaderValue::from_str(&format!("IPinfoClient/Rust/{}", VERSION))
457+
HeaderValue::from_str(&format!("IPinfoClient/Rust/{VERSION}"))
458458
.unwrap(),
459459
);
460460
headers.insert(
@@ -584,12 +584,12 @@ mod tests {
584584
let ip4 = &details["4.2.2.4"];
585585
assert_eq!(ip4.ip, "4.2.2.4");
586586
assert_eq!(ip4.hostname, Some("d.resolvers.level3.net".to_owned()));
587-
assert_eq!(ip4.city, "Broomfield");
588-
assert_eq!(ip4.region, "Colorado");
587+
assert_eq!(ip4.city, "Monroe");
588+
assert_eq!(ip4.region, "Louisiana");
589589
assert_eq!(ip4.country, "US");
590-
assert_eq!(ip4.loc, "39.8854,-105.1139");
591-
assert_eq!(ip4.postal, Some("80021".to_owned()));
592-
assert_eq!(ip4.timezone, Some("America/Denver".to_owned()));
590+
assert_eq!(ip4.loc, "32.5530,-92.0422");
591+
assert_eq!(ip4.postal, Some("71203".to_owned()));
592+
assert_eq!(ip4.timezone, Some("America/Chicago".to_owned()));
593593
}
594594

595595
#[tokio::test]

0 commit comments

Comments
 (0)