Skip to content

Commit 4ddfd34

Browse files
Merge pull request #28 from ipdata/claude/update-ipdata-api-5MQTy
Add Company endpoint and refactor ApiUrls to support custom base URLs
2 parents d3eb08e + 8413a85 commit 4ddfd34

15 files changed

Lines changed: 332 additions & 55 deletions

File tree

.github/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
- [Basic](#basic)
1212
- [Bulk](#bulk)
1313
- [Carrier](#carrier)
14+
- [Company](#company)
1415
- [Asn](#asn)
1516
- [Timezone](#timezone)
1617
- [Currency](#currency)
1718
- [Threat](#threat)
19+
- [EU Endpoint](#eu-endpoint)
1820
- [Contributing](#contributing)
1921
- [Versioning](#versioning)
2022
- [License](#license)
@@ -83,6 +85,15 @@ var carrierInfo = await client.Carrier("69.78.70.144");
8385
Console.WriteLine($"Carrier name: {carrierInfo.Name}");
8486
```
8587

88+
### Company
89+
90+
```csharp
91+
var client = new IpDataClient("API_KEY");
92+
93+
var companyInfo = await client.Company("69.78.70.144");
94+
Console.WriteLine($"Company name: {companyInfo.Name}");
95+
```
96+
8697
### ASN
8798

8899
```csharp
@@ -119,6 +130,16 @@ var threatInfo = await client.Threat("69.78.70.144");
119130
Console.WriteLine($"Threat is Tor: {threatInfo.IsTor}");
120131
```
121132

133+
## EU Endpoint
134+
135+
To ensure your data stays in the EU, use the EU endpoint by passing a custom base URL:
136+
137+
```csharp
138+
var client = new IpDataClient("API_KEY", new Uri("https://eu-api.ipdata.co"));
139+
140+
var ipInfo = await client.Lookup("8.8.8.8");
141+
```
142+
122143
## Contributing
123144

124145
Please read [CONTRIBUTING.md][CONTRIBUTING] for details on our code of conduct, and the process for submitting pull requests to us.

samples/IpData.Lookup/IpData.Lookup.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp3.0</TargetFramework>
5+
<TargetFramework>net8.0</TargetFramework>
66
<ApplicationIcon />
77
<StartupObject />
88
<LangVersion>latest</LangVersion>

src/IpData/Helpers/ApiUrls.cs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Globalization;
43
using System.Linq;
54
using System.Linq.Expressions;
@@ -8,48 +7,58 @@
87

98
namespace IpData.Helpers
109
{
11-
internal static class ApiUrls
10+
internal class ApiUrls
1211
{
13-
private static Uri Base => new Uri("https://api.ipdata.co");
12+
internal static readonly Uri DefaultBaseUrl = new Uri("https://api.ipdata.co");
1413

15-
public static Uri Get(string apiKey, CultureInfo culture) =>
16-
ApplyApiKey(new Uri(Base, $"{culture}"), apiKey);
14+
private readonly Uri _base;
1715

18-
public static Uri Get(string apiKey, string ip, CultureInfo culture)
16+
public ApiUrls(Uri baseUrl = null)
17+
{
18+
_base = baseUrl ?? DefaultBaseUrl;
19+
}
20+
21+
public Uri Get(string apiKey, CultureInfo culture) =>
22+
ApplyApiKey(new Uri(_base, $"{culture}"), apiKey);
23+
24+
public Uri Get(string apiKey, string ip, CultureInfo culture)
1925
{
2026
var relative = Equals(culture, CultureInfo.InvariantCulture) ? ip : $"{ip}/{culture}";
21-
return ApplyApiKey(new Uri(Base, relative), apiKey);
27+
return ApplyApiKey(new Uri(_base, relative), apiKey);
2228
}
2329

24-
public static Uri Get(string apiKey, string ip, Expression<Func<IpInfo, object>> expression)
30+
public Uri Get(string apiKey, string ip, Expression<Func<IpInfo, object>> expression)
2531
{
2632
var field = IpInfo.FieldName(expression);
27-
return ApplyApiKey(new Uri(Base, $"{ip}/{field}"), apiKey);
33+
return ApplyApiKey(new Uri(_base, $"{ip}/{field}"), apiKey);
2834
}
29-
30-
public static Uri Get(string apiKey, string ip, params Expression<Func<IpInfo, object>>[] expressions)
35+
36+
public Uri Get(string apiKey, string ip, params Expression<Func<IpInfo, object>>[] expressions)
3137
{
3238
var fields = string.Join(",", expressions.Select(IpInfo.FieldName));
33-
return ApplyApiKey(new Uri(Base, $"{ip}").AddParameter(nameof(fields), fields), apiKey);
39+
return ApplyApiKey(new Uri(_base, $"{ip}").AddParameter(nameof(fields), fields), apiKey);
3440
}
3541

36-
public static Uri Bulk(string apiKey) =>
37-
ApplyApiKey(new Uri(Base, "bulk"), apiKey);
42+
public Uri Bulk(string apiKey) =>
43+
ApplyApiKey(new Uri(_base, "bulk"), apiKey);
44+
45+
public Uri Carrier(string apiKey, string ip) =>
46+
ApplyApiKey(new Uri(_base, $"{ip}/carrier"), apiKey);
3847

39-
public static Uri Carrier(string apiKey, string ip) =>
40-
ApplyApiKey(new Uri(Base, $"{ip}/carrier"), apiKey);
48+
public Uri Asn(string apiKey, string ip) =>
49+
ApplyApiKey(new Uri(_base, $"asn/{ip}"), apiKey);
4150

42-
public static Uri Asn(string apiKey, string ip) =>
43-
ApplyApiKey(new Uri(Base, $"asn/{ip}"), apiKey);
51+
public Uri TimeZone(string apiKey, string ip) =>
52+
ApplyApiKey(new Uri(_base, $"{ip}/time_zone"), apiKey);
4453

45-
public static Uri TimeZone(string apiKey, string ip) =>
46-
ApplyApiKey(new Uri(Base, $"{ip}/time_zone"), apiKey);
54+
public Uri Currency(string apiKey, string ip) =>
55+
ApplyApiKey(new Uri(_base, $"{ip}/currency"), apiKey);
4756

48-
public static Uri Currency(string apiKey, string ip) =>
49-
ApplyApiKey(new Uri(Base, $"{ip}/currency"), apiKey);
57+
public Uri Threat(string apiKey, string ip) =>
58+
ApplyApiKey(new Uri(_base, $"{ip}/threat"), apiKey);
5059

51-
public static Uri Threat(string apiKey, string ip) =>
52-
ApplyApiKey(new Uri(Base, $"{ip}/threat"), apiKey);
60+
public Uri Company(string apiKey, string ip) =>
61+
ApplyApiKey(new Uri(_base, $"{ip}/company"), apiKey);
5362

5463
private static Uri ApplyApiKey(Uri url, string apiKey) =>
5564
url.AddParameter("api-key", apiKey);

src/IpData/IIpDataClient.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,23 @@ public interface IIpDataClient
1313
/// <summary>The IpData ApiKey.</summary>
1414
string ApiKey { get; }
1515

16+
/// <summary>Fetch company for IP.</summary>
17+
/// <param name="ip">The IPv4 address.</param>
18+
/// <returns>The company info <see cref="CompanyInfo"/>.</returns>
19+
/// <exception cref="Exceptions.BadRequestException">
20+
/// Thrown when IP address is private or invalid.
21+
/// </exception>
22+
/// <exception cref="Exceptions.ForbiddenException">
23+
/// Thrown when you have exceeded your daily plan quota.
24+
/// </exception>
25+
/// <exception cref="Exceptions.UnauthorizedException">
26+
/// Thrown when API key is not provided.
27+
/// </exception>
28+
/// <exception cref="Exceptions.ApiException">
29+
/// Thrown when unexpected case occurred.
30+
/// </exception>
31+
Task<CompanyInfo> Company(string ip);
32+
1633
/// <summary>Fetch carrier for IP.</summary>
1734
/// <param name="ip">The IPv4 address.</param>
1835
/// <returns>The carrier info <see cref="CarrierInfo"/>.</returns>

src/IpData/IpDataClient.cs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,50 @@ public class IpDataClient : IIpDataClient
2626
/// <summary>The HTTP client</summary>
2727
private readonly IHttpClient _httpClient;
2828

29+
/// <summary>The API URL builder</summary>
30+
private readonly ApiUrls _apiUrls;
31+
2932
/// <inheritdoc />
3033
public string ApiKey { get; }
3134

3235
/// <summary>Initializes a new instance of the <see cref="IpDataClient"/> class.</summary>
3336
/// <param name="apiKey">The API key.</param>
3437
public IpDataClient(string apiKey)
35-
: this(apiKey, new HttpClientAdapter())
38+
: this(apiKey, new HttpClientAdapter(), null)
3639
{
3740
}
3841

3942
/// <summary>Initializes a new instance of the <see cref="IpDataClient"/> class.</summary>
4043
/// <param name="apiKey">The API key.</param>
4144
/// <param name="httpClient">The HTTP client.</param>
4245
public IpDataClient(string apiKey, HttpClient httpClient)
43-
: this(apiKey, new HttpClientAdapter(httpClient))
46+
: this(apiKey, new HttpClientAdapter(httpClient), null)
4447
{
4548
}
4649

4750
/// <summary>Initializes a new instance of the <see cref="IpDataClient"/> class.</summary>
4851
/// <param name="apiKey">The API key.</param>
4952
/// <param name="httpClient">The HTTP client.</param>
53+
public IpDataClient(string apiKey, IHttpClient httpClient)
54+
: this(apiKey, httpClient, null)
55+
{
56+
}
57+
58+
/// <summary>Initializes a new instance of the <see cref="IpDataClient"/> class with a custom base URL.</summary>
59+
/// <param name="apiKey">The API key.</param>
60+
/// <param name="baseUrl">The base URL (e.g. https://eu-api.ipdata.co for the EU endpoint).</param>
61+
public IpDataClient(string apiKey, Uri baseUrl)
62+
: this(apiKey, new HttpClientAdapter(), baseUrl)
63+
{
64+
}
65+
66+
/// <summary>Initializes a new instance of the <see cref="IpDataClient"/> class.</summary>
67+
/// <param name="apiKey">The API key.</param>
68+
/// <param name="httpClient">The HTTP client.</param>
69+
/// <param name="baseUrl">The base URL. Defaults to https://api.ipdata.co when null.</param>
5070
/// <exception cref="ArgumentException">The {nameof(apiKey)} {apiKey} - apiKey</exception>
5171
/// <exception cref="ArgumentNullException">httpClient - The {nameof(httpClient)}</exception>
52-
public IpDataClient(string apiKey, IHttpClient httpClient)
72+
public IpDataClient(string apiKey, IHttpClient httpClient, Uri baseUrl)
5373
{
5474
if (string.IsNullOrWhiteSpace(apiKey))
5575
{
@@ -63,6 +83,7 @@ public IpDataClient(string apiKey, IHttpClient httpClient)
6383
$"The {nameof(httpClient)} can't be null");
6484

6585
ApiKey = apiKey;
86+
_apiUrls = new ApiUrls(baseUrl);
6687
}
6788

6889
/// <inheritdoc />
@@ -72,7 +93,7 @@ public Task<IpInfo> Lookup() =>
7293
/// <inheritdoc />
7394
public async Task<IpInfo> Lookup(CultureInfo culture)
7495
{
75-
var url = ApiUrls.Get(ApiKey, culture);
96+
var url = _apiUrls.Get(ApiKey, culture);
7697
var request = new HttpRequestMessage(HttpMethod.Get, url);
7798
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
7899
return _serializer.Deserialize<IpInfo>(json);
@@ -85,7 +106,7 @@ public Task<IpInfo> Lookup(string ip) =>
85106
/// <inheritdoc />
86107
public async Task<IpInfo> Lookup(string ip, CultureInfo culture)
87108
{
88-
var url = ApiUrls.Get(ApiKey, ip, culture);
109+
var url = _apiUrls.Get(ApiKey, ip, culture);
89110
var request = new HttpRequestMessage(HttpMethod.Get, url);
90111
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
91112
return _serializer.Deserialize<IpInfo>(json);
@@ -94,15 +115,15 @@ public async Task<IpInfo> Lookup(string ip, CultureInfo culture)
94115
/// <inheritdoc />
95116
public Task<string> Lookup(string ip, Expression<Func<IpInfo, object>> fieldSelector)
96117
{
97-
var url = ApiUrls.Get(ApiKey, ip, fieldSelector);
118+
var url = _apiUrls.Get(ApiKey, ip, fieldSelector);
98119
var request = new HttpRequestMessage(HttpMethod.Get, url);
99120
return SendRequestAsync(_httpClient, request);
100121
}
101122

102123
/// <inheritdoc />
103124
public async Task<IpInfo> Lookup(string ip, params Expression<Func<IpInfo, object>>[] fieldSelectors)
104125
{
105-
var url = ApiUrls.Get(ApiKey, ip, fieldSelectors);
126+
var url = _apiUrls.Get(ApiKey, ip, fieldSelectors);
106127
var request = new HttpRequestMessage(HttpMethod.Get, url);
107128
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
108129
return _serializer.Deserialize<IpInfo>(json);
@@ -111,7 +132,7 @@ public async Task<IpInfo> Lookup(string ip, params Expression<Func<IpInfo, objec
111132
/// <inheritdoc />
112133
public async Task<IEnumerable<IpInfo>> Lookup(IReadOnlyCollection<string> ips)
113134
{
114-
var url = ApiUrls.Bulk(ApiKey);
135+
var url = _apiUrls.Bulk(ApiKey);
115136
var request = new HttpRequestMessage(HttpMethod.Post, url)
116137
{
117138
Content = new StringContent(_serializer.Serialize(ips), Encoding.UTF8, "application/json")
@@ -121,10 +142,19 @@ public async Task<IEnumerable<IpInfo>> Lookup(IReadOnlyCollection<string> ips)
121142
return _serializer.Deserialize<IEnumerable<IpInfo>>(json);
122143
}
123144

145+
/// <inheritdoc />
146+
public async Task<CompanyInfo> Company(string ip)
147+
{
148+
var url = _apiUrls.Company(ApiKey, ip);
149+
var request = new HttpRequestMessage(HttpMethod.Get, url);
150+
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
151+
return _serializer.Deserialize<CompanyInfo>(json);
152+
}
153+
124154
/// <inheritdoc />
125155
public async Task<CarrierInfo> Carrier(string ip)
126156
{
127-
var url = ApiUrls.Carrier(ApiKey, ip);
157+
var url = _apiUrls.Carrier(ApiKey, ip);
128158
var request = new HttpRequestMessage(HttpMethod.Get, url);
129159
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
130160
return _serializer.Deserialize<CarrierInfo>(json);
@@ -133,7 +163,7 @@ public async Task<CarrierInfo> Carrier(string ip)
133163
/// <inheritdoc />
134164
public async Task<AsnInfo> Asn(string ip)
135165
{
136-
var url = ApiUrls.Asn(ApiKey, ip);
166+
var url = _apiUrls.Asn(ApiKey, ip);
137167
var request = new HttpRequestMessage(HttpMethod.Get, url);
138168
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
139169
return _serializer.Deserialize<AsnInfo>(json);
@@ -142,7 +172,7 @@ public async Task<AsnInfo> Asn(string ip)
142172
/// <inheritdoc />
143173
public async Task<Models.TimeZone> TimeZone(string ip)
144174
{
145-
var url = ApiUrls.TimeZone(ApiKey, ip);
175+
var url = _apiUrls.TimeZone(ApiKey, ip);
146176
var request = new HttpRequestMessage(HttpMethod.Get, url);
147177
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
148178
return _serializer.Deserialize<Models.TimeZone>(json);
@@ -151,7 +181,7 @@ public async Task<AsnInfo> Asn(string ip)
151181
/// <inheritdoc />
152182
public async Task<Currency> Currency(string ip)
153183
{
154-
var url = ApiUrls.Currency(ApiKey, ip);
184+
var url = _apiUrls.Currency(ApiKey, ip);
155185
var request = new HttpRequestMessage(HttpMethod.Get, url);
156186
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
157187
return _serializer.Deserialize<Currency>(json);
@@ -160,7 +190,7 @@ public async Task<Currency> Currency(string ip)
160190
/// <inheritdoc />
161191
public async Task<Threat> Threat(string ip)
162192
{
163-
var url = ApiUrls.Threat(ApiKey, ip);
193+
var url = _apiUrls.Threat(ApiKey, ip);
164194
var request = new HttpRequestMessage(HttpMethod.Get, url);
165195
var json = await SendRequestAsync(_httpClient, request).ConfigureAwait(false);
166196
return _serializer.Deserialize<Threat>(json);

src/IpData/Models/BlocklistInfo.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Newtonsoft.Json;
2+
3+
namespace IpData.Models
4+
{
5+
public class BlocklistInfo
6+
{
7+
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
8+
public string Name { get; set; }
9+
10+
[JsonProperty("site", NullValueHandling = NullValueHandling.Ignore)]
11+
public string Site { get; set; }
12+
13+
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
14+
public string Type { get; set; }
15+
}
16+
}

src/IpData/Models/CompanyInfo.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Newtonsoft.Json;
2+
3+
namespace IpData.Models
4+
{
5+
public class CompanyInfo
6+
{
7+
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
8+
public string Name { get; set; }
9+
10+
[JsonProperty("domain", NullValueHandling = NullValueHandling.Ignore)]
11+
public string Domain { get; set; }
12+
13+
[JsonProperty("network", NullValueHandling = NullValueHandling.Ignore)]
14+
public string Network { get; set; }
15+
16+
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
17+
public string Type { get; set; }
18+
}
19+
}

src/IpData/Models/IpInfo.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ public class IpInfo
7575
[JsonProperty("threat")]
7676
public Threat Threat { get; set; }
7777

78+
[JsonProperty("region_type", NullValueHandling = NullValueHandling.Ignore)]
79+
public string RegionType { get; set; }
80+
81+
[JsonProperty("carrier", NullValueHandling = NullValueHandling.Ignore)]
82+
public CarrierInfo Carrier { get; set; }
83+
84+
[JsonProperty("company", NullValueHandling = NullValueHandling.Ignore)]
85+
public CompanyInfo Company { get; set; }
86+
87+
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
88+
public int? Status { get; set; }
89+
7890
[JsonProperty("count")]
7991
public int Count { get; set; }
8092

src/IpData/Models/Language.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ public class Language
99

1010
[JsonProperty("native", NullValueHandling = NullValueHandling.Ignore)]
1111
public string Native { get; set; }
12+
13+
[JsonProperty("code", NullValueHandling = NullValueHandling.Ignore)]
14+
public string Code { get; set; }
1215
}
1316
}

0 commit comments

Comments
 (0)