Skip to content

Commit f8feb0e

Browse files
Merge pull request #20 from ipdata/fix-noticed-issues
Fix issues found during the connection-reuse review
2 parents e574984 + 7c91a05 commit f8feb0e

21 files changed

Lines changed: 189 additions & 73 deletions

‎.mvn/extensions.xml‎

Lines changed: 0 additions & 9 deletions
This file was deleted.

‎README.md‎

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ An 100% compliant [ipdata.co](https://ipdata.co) API java client.
99
- [Install](#install)
1010
- [Use](#use)
1111
- [Configuration](#configuration)
12-
- [API](#create-an-instance)
12+
- [API](#api)
1313
- [Basic Usage](#basic-usage)
1414
- [Connection reuse and HTTP/2](#connection-reuse-and-http2)
1515
- [Single Field Selection](#single-field-selection)
@@ -81,66 +81,84 @@ Output:
8181
{
8282
"ip": "1.1.1.1",
8383
"is_eu": false,
84-
"city": null,
85-
"region": null,
86-
"region_code": null,
87-
"region_type": null,
88-
"country_name": "Australia",
89-
"country_code": "AU",
90-
"continent_name": "Oceania",
91-
"continent_code": "OC",
92-
"latitude": -33.494,
93-
"longitude": 143.2104,
94-
"postal": null,
95-
"calling_code": "61",
96-
"flag": "https://ipdata.co/flags/au.png",
97-
"emoji_flag": "\ud83c\udde6\ud83c\uddfa",
98-
"emoji_unicode": "U+1F1E6 U+1F1FA",
84+
"is_satellite": false,
85+
"is_anycast": false,
86+
"city": "Los Angeles",
87+
"organisation": null,
88+
"region": "California",
89+
"region_code": "CA",
90+
"region_type": "state",
91+
"country_name": "United States",
92+
"country_code": "US",
93+
"continent_name": "North America",
94+
"continent_code": "NA",
95+
"latitude": 34.0522,
96+
"longitude": -118.2437,
97+
"postal": "90001",
98+
"calling_code": "1",
99+
"flag": "https://ipdata.co/flags/us.png",
100+
"emoji_flag": "\ud83c\uddfa\ud83c\uddf8",
101+
"emoji_unicode": "U+1F1FA U+1F1F8",
99102
"asn": {
100103
"asn": "AS13335",
101-
"name": "Cloudflare, Inc.",
104+
"name": "Cloudflare Inc",
102105
"domain": "cloudflare.com",
103106
"route": "1.1.1.0/24",
104107
"type": "hosting"
105108
},
109+
"carrier": {
110+
"name": "Cloudflare",
111+
"mcc": "310",
112+
"mnc": "000"
113+
},
106114
"company": {
107-
"name": "Cloudflare, Inc.",
115+
"name": "Cloudflare Inc",
108116
"domain": "cloudflare.com",
109117
"network": "1.1.1.0/24",
110118
"type": "hosting"
111119
},
112120
"languages": [
113121
{
114122
"name": "English",
115-
"native": "English"
123+
"native": "English",
124+
"code": "en",
125+
"rtl": 0
116126
}
117127
],
118128
"currency": {
119-
"name": "Australian Dollar",
120-
"code": "AUD",
121-
"symbol": "AU$",
129+
"name": "US Dollar",
130+
"code": "USD",
131+
"symbol": "$",
122132
"native": "$",
123-
"plural": "Australian dollars"
133+
"plural": "US dollars"
124134
},
125135
"time_zone": {
126-
"name": "Australia/Sydney",
127-
"abbr": "AEDT",
128-
"offset": "+1100",
136+
"name": "America/Los_Angeles",
137+
"abbr": "PDT",
138+
"offset": "-0700",
129139
"is_dst": true,
130-
"current_time": "2020-01-29T20:22:52.283874+11:00"
140+
"current_time": "2020-06-12T06:37:16.595612-07:00"
131141
},
132142
"threat": {
133143
"is_tor": false,
144+
"is_vpn": false,
134145
"is_proxy": false,
135146
"is_anonymous": false,
136147
"is_known_attacker": false,
137148
"is_known_abuser": false,
138149
"is_threat": false,
139150
"is_bogon": false,
140151
"is_icloud_relay": false,
141-
"is_datacenter": false
152+
"is_datacenter": false,
153+
"blocklists": [],
154+
"scores": {
155+
"vpn_score": 0,
156+
"proxy_score": 0,
157+
"threat_score": 0,
158+
"trust_score": 100
159+
}
142160
},
143-
"count": "0"
161+
"count": "1500"
144162
}
145163
```
146164

@@ -151,6 +169,7 @@ The following fields were added to the API responses recently and are mapped by
151169
- `threat.blocklists[].first_seen` – `Blocklist.getFirstSeen()`: the first day the address was seen on that blocklist, as a `YYYY-MM-DD` (UTC) string, or `null` when the feed does not report it.
152170
- `threat.blocklists[].last_seen` – `Blocklist.getLastSeen()`: the most recent such day, same format, or `null`.
153171
- `threat.blocklists[].days_seen` – `Blocklist.getDaysSeen()`: the number of days the address was seen on that blocklist, as an `Integer`, or `null`.
172+
- `languages[].code` – `Language.code()`: the code of the language (`en` for English), or `null` when the API does not send it.
154173

155174
#### Connection reuse and HTTP/2
156175
An `IpdataService` keeps a persistent HTTPS connection pool for as long as it lives. Create one service per process (or one per API key or endpoint), keep it, and reuse it for every lookup: each new service pays a fresh TLS handshake. Requests to api.ipdata.co are multiplexed over HTTP/2 when the platform negotiates it, and fall back to HTTP/1.1 keep-alive otherwise.
@@ -206,7 +225,7 @@ IpdataModel flags = ipdataService.getFields("1.1.1.1", IpdataField.IS_SATELLITE,
206225

207226
```
208227

209-
### Bulk data
228+
#### Bulk data
210229
You can as well get multiple responses at once by using the ``bulk`` api:
211230

212231
```java

‎pom.xml‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
<version.build.jacoco>0.8.14</version.build.jacoco>
4141
<version.build.surefire>3.5.5</version.build.surefire>
4242
<version.client.feign>11.10</version.client.feign>
43+
<version.client.jackson>2.22.4</version.client.jackson>
44+
<!-- jackson-annotations is released once per minor line (2.20, 2.21, 2.22, ...) -->
45+
<version.client.jackson.annotations>2.22</version.client.jackson.annotations>
4346
</properties>
4447
<dependencies>
4548
<dependency>
@@ -57,6 +60,16 @@
5760
<artifactId>feign-java11</artifactId>
5861
<version>${version.client.feign}</version>
5962
</dependency>
63+
<dependency>
64+
<groupId>com.fasterxml.jackson.core</groupId>
65+
<artifactId>jackson-databind</artifactId>
66+
<version>${version.client.jackson}</version>
67+
</dependency>
68+
<dependency>
69+
<groupId>com.fasterxml.jackson.core</groupId>
70+
<artifactId>jackson-annotations</artifactId>
71+
<version>${version.client.jackson.annotations}</version>
72+
</dependency>
6073
<dependency>
6174
<groupId>io.github.openfeign</groupId>
6275
<artifactId>feign-httpclient</artifactId>
@@ -66,7 +79,7 @@
6679
<dependency>
6780
<groupId>com.google.guava</groupId>
6881
<artifactId>guava</artifactId>
69-
<version>33.4.8-jre</version>
82+
<version>33.7.2-jre</version>
7083
</dependency>
7184
<dependency>
7285
<groupId>org.slf4j</groupId>

‎src/main/java/io/ipdata/client/model/Language.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ public class Language {
1010
private String name;
1111
@JsonProperty("native")
1212
private String nativeName;
13+
/** The language code, for example {@code en} for English; {@code null} when the API does not send it. */
14+
private String code;
1315
private int rtl;
1416
}

‎src/main/java/io/ipdata/client/service/ApiErrorDecoder.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.io.IOException;
1515
import java.net.URL;
16+
import java.nio.charset.StandardCharsets;
1617

1718
@RequiredArgsConstructor
1819
@Slf4j
@@ -30,7 +31,7 @@ public Exception decode(String methodKey, Response response) {
3031
URL url = new URL(response.request().url());
3132
logger.error("An error occurred during an Ipdata API call: got status '{}' for path '{}'",
3233
responseCode, url.getPath());
33-
message = CharStreams.toString(response.body().asReader());
34+
message = CharStreams.toString(response.body().asReader(StandardCharsets.UTF_8));
3435
Error error = mapper.readValue(message, Error.class);
3536
if (responseCode == RATE_LIMIT_STATUS) {
3637
return new RateLimitException(error.getMessage(), responseCode);

‎src/main/java/io/ipdata/client/service/FieldDecoder.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.io.IOException;
1010
import java.lang.reflect.Type;
11+
import java.nio.charset.StandardCharsets;
1112

1213
/**
1314
* The API returns usable but invalid(/unquoted) strings for String fields
@@ -22,7 +23,7 @@ class FieldDecoder implements Decoder {
2223
@Override
2324
public Object decode(Response response, Type type) throws IOException {
2425
if (type.equals(String.class)) {
25-
return CharStreams.toString(response.body().asReader());
26+
return CharStreams.toString(response.body().asReader(StandardCharsets.UTF_8));
2627
}
2728
return mapper.readValue(response.body().asInputStream(), mapper.constructType(type));
2829
}

‎src/main/java/io/ipdata/client/service/IpdataServiceBuilder.java‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.slf4j.LoggerFactory;
2020

2121
import java.net.URL;
22+
import java.time.Duration;
2223

2324
import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE;
2425

@@ -64,7 +65,7 @@ public static IpdataServiceBuilder of(URL url, String key, CacheConfig cacheConf
6465
public IpdataService build() {
6566
final ObjectMapper mapper = new ObjectMapper();
6667
mapper.setPropertyNamingStrategy(SNAKE_CASE);
67-
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
68+
mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
6869
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
6970
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
7071

@@ -98,13 +99,14 @@ public IpdataService build() {
9899
.target(IpdataInternalSingleFieldClient.class, url.toString());
99100

100101
if (cacheConfig != null) {
102+
final Duration expiry = Duration.of(cacheConfig.timeout(), cacheConfig.unit().toChronoUnit());
101103
CachingInternalClient cachingInternalClient = CachingInternalClient.builder()
102104
.expiry(cacheConfig.timeout())
103105
.unit(cacheConfig.unit())
104106
.maxSize(cacheConfig.maxSize())
105107
.ipdataCache(
106108
CacheBuilder.newBuilder()
107-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
109+
.expireAfterWrite(expiry)
108110
.maximumSize(cacheConfig.maxSize())
109111
.build(new CacheLoader<String, IpdataModel>() {
110112
@Override
@@ -115,7 +117,7 @@ public IpdataModel load(String key) throws Exception {
115117
)
116118
.fieldsCache(
117119
CacheBuilder.newBuilder()
118-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
120+
.expireAfterWrite(expiry)
119121
.maximumSize(cacheConfig.maxSize())
120122
.build(new CacheLoader<HashPair<String, String>, IpdataModel>() {
121123
@Override
@@ -126,7 +128,7 @@ public IpdataModel load(HashPair<String, String> key) throws Exception {
126128
)
127129
.asnCache(
128130
CacheBuilder.newBuilder()
129-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
131+
.expireAfterWrite(expiry)
130132
.maximumSize(cacheConfig.maxSize())
131133
.build(new CacheLoader<String, AsnModel>() {
132134
@Override
@@ -137,7 +139,7 @@ public AsnModel load(String key) throws Exception {
137139
)
138140
.tzCache(
139141
CacheBuilder.newBuilder()
140-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
142+
.expireAfterWrite(expiry)
141143
.maximumSize(cacheConfig.maxSize())
142144
.build(new CacheLoader<String, TimeZone>() {
143145
@Override
@@ -148,7 +150,7 @@ public TimeZone load(String key) throws Exception {
148150
)
149151
.currencyCache(
150152
CacheBuilder.newBuilder()
151-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
153+
.expireAfterWrite(expiry)
152154
.maximumSize(cacheConfig.maxSize())
153155
.build(new CacheLoader<String, Currency>() {
154156
@Override
@@ -159,7 +161,7 @@ public Currency load(String key) throws Exception {
159161
)
160162
.threatCache(
161163
CacheBuilder.newBuilder()
162-
.expireAfterWrite(cacheConfig.timeout(), cacheConfig.unit())
164+
.expireAfterWrite(expiry)
163165
.maximumSize(cacheConfig.maxSize())
164166
.build(new CacheLoader<String, ThreatModel>() {
165167
@Override

‎src/main/java/io/ipdata/client/service/IpdataServiceSupport.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ class IpdataServiceSupport implements IpdataService {
2121
private final IpdataInternalSingleFieldClient singleFieldClient;
2222

2323
@Delegate(types = IpdataInternalClient.class)
24-
public IpdataInternalClient getSingleFieldClient() {
24+
private IpdataInternalClient getApi() {
2525
return api;
2626
}
2727

2828
@Delegate(types = IpdataInternalSingleFieldClient.class)
29-
private IpdataInternalSingleFieldClient getApi() {
29+
private IpdataInternalSingleFieldClient getSingleFieldClient() {
3030
return singleFieldClient;
3131
}
3232

‎src/main/java/io/ipdata/client/service/Ipv6SafeClient.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public Response execute(Request request, Request.Options options) throws IOExcep
3636
String fixedUrl = fixedPath + query;
3737
request = Request.create(
3838
request.httpMethod(), fixedUrl, request.headers(),
39-
request.body(), request.charset()
39+
request.body(), request.charset(), request.requestTemplate()
4040
);
4141
}
4242
return delegate.execute(request, options);

0 commit comments

Comments
 (0)