Skip to content

Commit

Permalink
#149: Allow HTTP requests with data compression enhancement (#150)
Browse files Browse the repository at this point in the history
* Add getUTxOInfo Tests

* Add API Token example to Readme

* New Feature #149: Allow HTTP requests with data compression

* Fix AddressInfo Endpoint

* Change Default Timeout Val to 300 Seconds

---------

Co-authored-by: Dudi Edri <[email protected]>
  • Loading branch information
edridudi and Dudi Edri authored Nov 15, 2023
1 parent 6efbfe5 commit 8b350d3
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 38 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca
- Sorting Supported
- API Token Supported
- Inner Retry Mechanism upon Timeouts
- HTTP GZIP Compression Supported
<details open>
<summary>Supported REST Services</summary>
<table>
Expand Down Expand Up @@ -334,7 +335,7 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca

| Koios Instance | Koios Java Client |
|:--------------:|:-----------------:|
| 1.1.0 | 1.18.0 |
| 1.1.0 | 1.18.1 |
| 1.0.10 | 1.17.3 |
| 1.0.9 | 1.16.3 |
| 1.0.8 | 1.15.2 |
Expand All @@ -351,13 +352,13 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca
<dependency>
<groupId>io.github.cardano-community</groupId>
<artifactId>koios-java-client</artifactId>
<version>1.18.0</version>
<version>1.18.1</version>
</dependency>
```

- For Gradle, add the following dependency to build.gradle
```
compile group: 'io.github.cardano-community', name: 'koios-java-client', version: '1.18.0'
compile group: 'io.github.cardano-community', name: 'koios-java-client', version: '1.18.1'
```

### Get Koios Backend Service (No API Token)
Expand Down Expand Up @@ -424,9 +425,10 @@ Result<List<TxHash>> transactionsResult = addressService.getAddressTransactions(
|------------------------------------|:-------:|----------------------------------------------------------------|:-------:|
| KOIOS_JAVA_LIB_LOGGING | boolean | Toggle Logging | false |
| KOIOS_JAVA_LIB_RETRIES_COUNT | integer | Sets the max retry count upon request timeout | 5 |
| KOIOS_JAVA_LIB_READ_TIMEOUT_SEC | integer | Sets the default read timeout for new connections (seconds) | 60 |
| KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC | integer | Sets the default connect timeout for new connections (seconds) | 60 |
| KOIOS_JAVA_LIB_READ_TIMEOUT_SEC | integer | Sets the default read timeout for new connections (seconds) | 300 |
| KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC | integer | Sets the default connect timeout for new connections (seconds) | 300 |
| KOIOS_JAVA_LIB_RETRY_ON_TIMEOUT | boolean | Sets whether to retry upon request timeout | true |
| KOIOS_JAVA_LIB_GZIP_COMPRESSION | boolean | Sets whether to use GZIP Compression | true |

## Clone & Build with Maven
```shell
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.cardano-community</groupId>
<artifactId>koios-java-client</artifactId>
<version>1.18.0</version>
<version>1.18.1</version>
<name>${project.groupId}:${project.artifactId}</name>
<description>Koios Java Client is a Java REST Client library which allows interacting with Koios Server Instances using Java Objects</description>
<url>https://github.com/cardano-community/koios-java-client</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public interface AddressService {
* @return Result of Type List of {@link AddressInfo} with Balance, Stake Address, UTxO set associated with the specified address.
* @throws ApiException if an error occurs while attempting to invoke the API
*/
Result<AddressInfo> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException;
Result<List<AddressInfo>> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException;

/**
* Address UTXOs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package rest.koios.client.backend.api.address.impl;

import rest.koios.client.backend.api.address.api.AddressApi;
import rest.koios.client.backend.api.address.AddressService;
import rest.koios.client.backend.api.address.api.AddressApi;
import rest.koios.client.backend.api.address.model.AddressAsset;
import rest.koios.client.backend.api.address.model.AddressInfo;
import rest.koios.client.backend.api.base.BaseService;
import rest.koios.client.backend.api.base.Result;
import rest.koios.client.backend.api.base.common.TxHash;
import rest.koios.client.backend.api.base.common.UTxO;
import rest.koios.client.backend.api.base.exception.ApiException;
import rest.koios.client.backend.api.base.common.TxHash;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.backend.factory.options.SortType;
import retrofit2.Call;
Expand Down Expand Up @@ -40,25 +40,37 @@ public AddressServiceImpl(String baseUrl, String apiToken) {

@Override
public Result<AddressInfo> getAddressInformation(String address) throws ApiException {
return getAddressInformation(List.of(address), SortType.DESC, null);
validateBech32(address);
Call<List<AddressInfo>> call = addressApi.getAddressInformation(buildBody("_addresses", List.of(address), null), optionsToParamMap(Options.EMPTY));
try {
Response<List<AddressInfo>> response = (Response) execute(call);
Result<AddressInfo> result = processResponseGetOne(response);
if (result.isSuccessful()) {
result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet()));
}
return result;
} catch (IOException e) {
throw new ApiException(e.getMessage(), e);
}
}

@Override
public Result<AddressInfo> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException {
public Result<List<AddressInfo>> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException {
for (String address : addressList) {
validateBech32(address);
}
Call<List<AddressInfo>> call = addressApi.getAddressInformation(buildBody("_addresses", addressList, null), optionsToParamMap(options));
try {
Response<List<AddressInfo>> response = (Response) execute(call);
Result<AddressInfo> result = processResponseGetOne(response);
Result<List<AddressInfo>> result = processResponse(response);
if (result.isSuccessful()) {
//Sort
if (utxoSortType == SortType.DESC) {
result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet()).descendingSet());
} else {
result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet()));
}
result.getValue().forEach(addressInfo -> {
if (utxoSortType == SortType.DESC) {
addressInfo.setUtxoSet(new TreeSet<>(addressInfo.getUtxoSet()).descendingSet());
} else {
addressInfo.setUtxoSet(new TreeSet<>(addressInfo.getUtxoSet()));
}
});
}
return result;
} catch (IOException e) {
Expand Down
49 changes: 29 additions & 20 deletions src/main/java/rest/koios/client/backend/api/base/BaseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import okhttp3.logging.HttpLoggingInterceptor;
import org.jetbrains.annotations.NotNull;
import rest.koios.client.backend.api.base.exception.ApiException;
import rest.koios.client.backend.api.base.interceptor.GzipInterceptor;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.utils.Bech32Util;
import retrofit2.Call;
Expand Down Expand Up @@ -37,6 +38,9 @@ public class BaseService {
private static final int SLEEP_TIME_MILLIS = 2000;
private boolean retryOnTimeout = true;
private final String apiToken;
private int readTimeoutSec = 300;
private int connectTimeoutSec = 300;
private boolean gzipCompression = true;

/**
* Base Service Constructor
Expand All @@ -55,8 +59,23 @@ public BaseService(String baseUrl) {
*/
public BaseService(String baseUrl, String apiToken) {
this.apiToken = apiToken;
int readTimeoutSec = getReadTimeoutSec();
int connectTimeoutSec = getConnectTimeoutSec();

String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_READ_TIMEOUT_SEC");
if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) {
int readTimeoutSec = Integer.parseInt(strReadTimeoutSec);
if (readTimeoutSec >= 1) {
this.readTimeoutSec = readTimeoutSec;
}
}

String strConnectTimeoutSec = System.getenv("KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC");
if (strConnectTimeoutSec != null && !strConnectTimeoutSec.isEmpty()) {
int connectTimeoutSec = Integer.parseInt(strConnectTimeoutSec);
if (connectTimeoutSec >= 1) {
this.connectTimeoutSec = connectTimeoutSec;
}
}

boolean logging = Boolean.parseBoolean(System.getenv("KOIOS_JAVA_LIB_LOGGING"));
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.readTimeout(readTimeoutSec, TimeUnit.SECONDS)
Expand All @@ -81,6 +100,14 @@ public okhttp3.Response intercept(@NotNull Chain chain) throws IOException {
}
});
}

if (System.getenv("KOIOS_JAVA_LIB_GZIP_COMPRESSION") != null) {
gzipCompression = Boolean.parseBoolean(System.getenv("KOIOS_JAVA_LIB_GZIP_COMPRESSION"));
}
if (gzipCompression) {
okHttpClientBuilder.addInterceptor(new GzipInterceptor());
}

String strRetries = System.getenv("KOIOS_JAVA_LIB_RETRIES_COUNT");
if (strRetries != null && !strRetries.isEmpty()) {
retriesCount = Math.max(Integer.parseInt(strRetries), 1);
Expand All @@ -95,24 +122,6 @@ public okhttp3.Response intercept(@NotNull Chain chain) throws IOException {
.create(objectMapper)).build();
}

private int getReadTimeoutSec() {
int readTimeoutSec = 60;
String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_READ_TIMEOUT_SEC");
if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) {
readTimeoutSec = Integer.parseInt(strReadTimeoutSec);
}
return readTimeoutSec >= 1 ? readTimeoutSec : 60;
}

private int getConnectTimeoutSec() {
int connectTimeoutSec = 60;
String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC");
if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) {
connectTimeoutSec = Integer.parseInt(strReadTimeoutSec);
}
return connectTimeoutSec >= 1 ? connectTimeoutSec : 60;
}

protected <T> Result<T> processResponseGetOne(Response<List<T>> response) throws IOException {
if (response.isSuccessful()) {
if (response.body() != null && !response.body().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package rest.koios.client.backend.api.base.interceptor;


import java.io.IOException;
import java.util.Objects;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.GzipSource;
import okio.Okio;
import org.jetbrains.annotations.NotNull;

public class GzipInterceptor implements Interceptor {
@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder newRequest = chain.request().newBuilder();
newRequest.addHeader("Accept-Encoding", "deflate, gzip");
Response response = chain.proceed(newRequest.build());

if (isGzipped(response)) {
return unzip(response);
} else {
return response;
}
}

private Response unzip(final Response response) throws IOException {

if (response.body() == null) {
return response;
}

GzipSource gzipSource = new GzipSource(response.body().source());
String bodyString = Okio.buffer(gzipSource).readUtf8();

ResponseBody responseBody = ResponseBody.create(bodyString, response.body().contentType());

Headers strippedHeaders = response.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
return response.newBuilder()
.headers(strippedHeaders)
.body(responseBody)
.message(response.message())
.build();

}

private Boolean isGzipped(Response response) {
return response.header("Content-Encoding") != null && Objects.equals(response.header("Content-Encoding"), "gzip");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import rest.koios.client.backend.api.base.exception.ApiException;
import rest.koios.client.backend.factory.BackendFactory;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.backend.factory.options.SortType;

import java.util.List;

Expand All @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr1qy2jt0qpqz2z2z9zx5w4xemekkce7yderz53kjue53lpqv90lkfa9sgrfjuz6uvt4uqtrqhl2kj0a9lnr9ndzutx32gqleeckv",
"addr1q9xvgr4ehvu5k5tmaly7ugpnvekpqvnxj8xy50pa7kyetlnhel389pa4rnq6fmkzwsaynmw0mnldhlmchn2sfd589fgsz9dd0y");
Result<List<AddressInfo>> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY);
Assertions.assertTrue(addressInformationResult.isSuccessful());
Assertions.assertNotNull(addressInformationResult.getValue());
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationBadRequestTest() {
String address = "a123sd";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import rest.koios.client.backend.api.base.common.TxHash;
import rest.koios.client.backend.factory.BackendFactory;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.backend.factory.options.SortType;

import java.util.List;

Expand All @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr_test1vzpwq95z3xyum8vqndgdd9mdnmafh3djcxnc6jemlgdmswcve6tkw",
"addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc");
Result<List<AddressInfo>> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY);
Assertions.assertTrue(addressInformationResult.isSuccessful());
Assertions.assertNotNull(addressInformationResult.getValue());
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationBadRequestTest() {
String address = "a123sd";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import rest.koios.client.backend.api.base.exception.ApiException;
import rest.koios.client.backend.factory.BackendFactory;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.backend.factory.options.SortType;

import java.util.List;

Expand All @@ -38,6 +39,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc",
"addr_test1vqneq3v0dqh3x3muv6ee3lt8e5729xymnxuavx6tndcjc2cv24ef9");
Result<List<AddressInfo>> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY);
Assertions.assertTrue(addressInformationResult.isSuccessful());
Assertions.assertNotNull(addressInformationResult.getValue());
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationBadRequestTest() {
String address = "a123sd";
Expand Down

0 comments on commit 8b350d3

Please sign in to comment.