From 479b82c5d74698999f07bb6494cd0f4c6f39a1bd Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Tue, 3 Oct 2023 17:56:30 -0700 Subject: [PATCH 1/4] feat: Introduce error types and retries --- .openapi-generator/FILES | 6 + .../java/dev/openfga/sdk/api/OpenFgaApi.java | 640 +++++++----------- .../openfga/sdk/api/auth/OAuth2Client.java | 33 +- .../dev/openfga/sdk/api/client/ApiClient.java | 11 + .../sdk/api/client/HttpRequestAttempt.java | 114 ++++ .../api/configuration/BaseConfiguration.java | 4 + .../configuration/ClientConfiguration.java | 12 + .../sdk/api/configuration/Configuration.java | 28 + .../configuration/ConfigurationOverride.java | 22 + .../sdk/errors/FgaApiAuthenticationError.java | 14 + .../sdk/errors/FgaApiInternalError.java | 14 + .../sdk/errors/FgaApiNotFoundError.java | 14 + .../errors/FgaApiRateLimitExceededError.java | 14 + .../sdk/errors/FgaApiValidationError.java | 14 + .../dev/openfga/sdk/api/OpenFgaApiTest.java | 43 +- .../sdk/api/auth/OAuth2ClientTest.java | 9 +- .../sdk/api/client/OpenFgaClientTest.java | 41 +- 17 files changed, 582 insertions(+), 451 deletions(-) create mode 100644 src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java create mode 100644 src/main/java/dev/openfga/sdk/errors/FgaApiAuthenticationError.java create mode 100644 src/main/java/dev/openfga/sdk/errors/FgaApiInternalError.java create mode 100644 src/main/java/dev/openfga/sdk/errors/FgaApiNotFoundError.java create mode 100644 src/main/java/dev/openfga/sdk/errors/FgaApiRateLimitExceededError.java create mode 100644 src/main/java/dev/openfga/sdk/errors/FgaApiValidationError.java diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 5b3f3b6..966dcc2 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -90,6 +90,7 @@ src/main/java/dev/openfga/sdk/api/client/ClientListRelationsRequest.java src/main/java/dev/openfga/sdk/api/client/ClientReadRequest.java src/main/java/dev/openfga/sdk/api/client/ClientTupleKey.java src/main/java/dev/openfga/sdk/api/client/ClientWriteRequest.java +src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java src/main/java/dev/openfga/sdk/api/configuration/ApiToken.java src/main/java/dev/openfga/sdk/api/configuration/BaseConfiguration.java @@ -166,6 +167,11 @@ src/main/java/dev/openfga/sdk/api/model/WriteAuthorizationModelRequest.java src/main/java/dev/openfga/sdk/api/model/WriteAuthorizationModelResponse.java src/main/java/dev/openfga/sdk/api/model/WriteRequest.java src/main/java/dev/openfga/sdk/errors/ApiException.java +src/main/java/dev/openfga/sdk/errors/FgaApiAuthenticationError.java +src/main/java/dev/openfga/sdk/errors/FgaApiInternalError.java +src/main/java/dev/openfga/sdk/errors/FgaApiNotFoundError.java +src/main/java/dev/openfga/sdk/errors/FgaApiRateLimitExceededError.java +src/main/java/dev/openfga/sdk/errors/FgaApiValidationError.java src/main/java/dev/openfga/sdk/errors/FgaInvalidParameterException.java src/main/java/dev/openfga/sdk/util/Pair.java src/main/java/dev/openfga/sdk/util/StringUtil.java diff --git a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java index f5be21a..6c01c0f 100644 --- a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java +++ b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java @@ -13,7 +13,6 @@ package dev.openfga.sdk.api; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import dev.openfga.sdk.api.auth.*; import dev.openfga.sdk.api.client.*; import dev.openfga.sdk.api.configuration.*; @@ -40,9 +39,7 @@ import dev.openfga.sdk.errors.*; import dev.openfga.sdk.util.Pair; import java.io.IOException; -import java.io.InputStream; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; @@ -50,7 +47,6 @@ import java.util.List; import java.util.StringJoiner; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; /** * A low-level API representation of an OpenFGA server. @@ -58,28 +54,21 @@ * Most code should favor the simpler and higher-level {@link OpenFgaClient} when calling an OpenFGA server. */ public class OpenFgaApi { - private final HttpClient memberVarHttpClient; - private final ObjectMapper memberVarObjectMapper; private final Configuration configuration; + + private final ApiClient apiClient; private final OAuth2Client oAuth2Client; - private final Consumer memberVarInterceptor; - private final Consumer> memberVarResponseInterceptor; - private final Consumer> memberVarAsyncResponseInterceptor; public OpenFgaApi(Configuration configuration) throws FgaInvalidParameterException { this(configuration, new ApiClient()); } public OpenFgaApi(Configuration configuration, ApiClient apiClient) throws FgaInvalidParameterException { - memberVarHttpClient = apiClient.getHttpClient(); - memberVarObjectMapper = apiClient.getObjectMapper(); + this.apiClient = apiClient; this.configuration = configuration; - memberVarInterceptor = apiClient.getRequestInterceptor(); - memberVarResponseInterceptor = apiClient.getResponseInterceptor(); - memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor(); if (configuration.getCredentials().getCredentialsMethod() == CredentialsMethod.CLIENT_CREDENTIALS) { - this.oAuth2Client = new OAuth2Client(configuration, apiClient.getHttpClient(), apiClient.getObjectMapper()); + this.oAuth2Client = new OAuth2Client(configuration, apiClient); } else { this.oAuth2Client = null; } @@ -116,24 +105,10 @@ public CompletableFuture check( private CompletableFuture check(String storeId, CheckRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = checkRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("check", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = + checkRequestBuilder(storeId, body, configuration).build(); + return new HttpRequestAttempt<>(request, "check", CheckResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -172,11 +147,13 @@ private CompletableFuture> checkWithHttpInfo( throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = checkRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("check", localVarResponse)); @@ -188,8 +165,9 @@ private CompletableFuture> checkWithHttpInfo( localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue(responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -228,7 +206,7 @@ private HttpRequest.Builder checkRequestBuilder(String storeId, CheckRequest bod } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -237,8 +215,8 @@ private HttpRequest.Builder checkRequestBuilder(String storeId, CheckRequest bod if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -272,24 +250,9 @@ public CompletableFuture createStore( private CompletableFuture createStore(CreateStoreRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = createStoreRequestBuilder(body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("createStore", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = createStoreRequestBuilder(body, configuration).build(); + return new HttpRequestAttempt<>(request, "createStore", CreateStoreResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -325,11 +288,13 @@ private CompletableFuture> createStoreWithHttpI CreateStoreRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = createStoreRequestBuilder(body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("createStore", localVarResponse)); @@ -341,8 +306,11 @@ private CompletableFuture> createStoreWithHttpI localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -377,7 +345,7 @@ private HttpRequest.Builder createStoreRequestBuilder(CreateStoreRequest body, C } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -386,8 +354,8 @@ private HttpRequest.Builder createStoreRequestBuilder(CreateStoreRequest body, C if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -419,15 +387,10 @@ public CompletableFuture deleteStore(String storeId, ConfigurationOverride private CompletableFuture deleteStore(String storeId, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = deleteStoreRequestBuilder(storeId, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("deleteStore", localVarResponse)); - } - return CompletableFuture.completedFuture(null); - }); + HttpRequest request = + deleteStoreRequestBuilder(storeId, configuration).build(); + return new HttpRequestAttempt<>(request, "deleteStore", Void.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -463,11 +426,13 @@ private CompletableFuture> deleteStoreWithHttpInfo(String stor throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = deleteStoreRequestBuilder(storeId, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("deleteStore", localVarResponse)); @@ -510,8 +475,8 @@ private HttpRequest.Builder deleteStoreRequestBuilder(String storeId, Configurat if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -547,24 +512,10 @@ public CompletableFuture expand( private CompletableFuture expand(String storeId, ExpandRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = expandRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("expand", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = + expandRequestBuilder(storeId, body, configuration).build(); + return new HttpRequestAttempt<>(request, "expand", ExpandResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -603,11 +554,13 @@ private CompletableFuture> expandWithHttpInfo( throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = expandRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("expand", localVarResponse)); @@ -619,8 +572,9 @@ private CompletableFuture> expandWithHttpInfo( localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue(responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -660,7 +614,7 @@ private HttpRequest.Builder expandRequestBuilder(String storeId, ExpandRequest b } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -669,8 +623,8 @@ private HttpRequest.Builder expandRequestBuilder(String storeId, ExpandRequest b if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -703,24 +657,9 @@ public CompletableFuture getStore(String storeId, Configuratio private CompletableFuture getStore(String storeId, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = getStoreRequestBuilder(storeId, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("getStore", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = getStoreRequestBuilder(storeId, configuration).build(); + return new HttpRequestAttempt<>(request, "getStore", GetStoreResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -756,11 +695,13 @@ private CompletableFuture> getStoreWithHttpInfo( String storeId, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = getStoreRequestBuilder(storeId, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("getStore", localVarResponse)); @@ -772,8 +713,10 @@ private CompletableFuture> getStoreWithHttpInfo( localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -811,8 +754,8 @@ private HttpRequest.Builder getStoreRequestBuilder(String storeId, Configuration if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -849,24 +792,10 @@ private CompletableFuture listObjects( String storeId, ListObjectsRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = listObjectsRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("listObjects", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = + listObjectsRequestBuilder(storeId, body, configuration).build(); + return new HttpRequestAttempt<>(request, "listObjects", ListObjectsResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -905,11 +834,13 @@ private CompletableFuture> listObjectsWithHttpI throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = listObjectsRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("listObjects", localVarResponse)); @@ -921,8 +852,11 @@ private CompletableFuture> listObjectsWithHttpI localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -963,7 +897,7 @@ private HttpRequest.Builder listObjectsRequestBuilder( } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -972,8 +906,8 @@ private HttpRequest.Builder listObjectsRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1010,25 +944,10 @@ private CompletableFuture listStores( Integer pageSize, String continuationToken, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - listStoresRequestBuilder(pageSize, continuationToken, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("listStores", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = listStoresRequestBuilder(pageSize, continuationToken, configuration) + .build(); + return new HttpRequestAttempt<>(request, "listStores", ListStoresResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1068,11 +987,13 @@ private CompletableFuture> listStoresWithHttpInf try { HttpRequest.Builder localVarRequestBuilder = listStoresRequestBuilder(pageSize, continuationToken, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("listStores", localVarResponse)); @@ -1084,8 +1005,10 @@ private CompletableFuture> listStoresWithHttpInf localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1138,8 +1061,8 @@ private HttpRequest.Builder listStoresRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1175,24 +1098,10 @@ public CompletableFuture read( private CompletableFuture read(String storeId, ReadRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = readRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("read", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = + readRequestBuilder(storeId, body, configuration).build(); + return new HttpRequestAttempt<>(request, "read", ReadResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1231,11 +1140,13 @@ private CompletableFuture> readWithHttpInfo( throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = readRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("read", localVarResponse)); @@ -1247,8 +1158,9 @@ private CompletableFuture> readWithHttpInfo( localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue(responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1287,7 +1199,7 @@ private HttpRequest.Builder readRequestBuilder(String storeId, ReadRequest body, } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -1296,8 +1208,8 @@ private HttpRequest.Builder readRequestBuilder(String storeId, ReadRequest body, if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1334,25 +1246,11 @@ private CompletableFuture readAssertions( String storeId, String authorizationModelId, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - readAssertionsRequestBuilder(storeId, authorizationModelId, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("readAssertions", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = readAssertionsRequestBuilder(storeId, authorizationModelId, configuration) + .build(); + return new HttpRequestAttempt<>( + request, "readAssertions", ReadAssertionsResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1393,11 +1291,13 @@ private CompletableFuture> readAssertionsWit try { HttpRequest.Builder localVarRequestBuilder = readAssertionsRequestBuilder(storeId, authorizationModelId, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("readAssertions", localVarResponse)); @@ -1409,8 +1309,11 @@ private CompletableFuture> readAssertionsWit localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1456,8 +1359,8 @@ private HttpRequest.Builder readAssertionsRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1493,27 +1396,15 @@ public CompletableFuture readAuthorizationModel( private CompletableFuture readAuthorizationModel( String storeId, String id, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - readAuthorizationModelRequestBuilder(storeId, id, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture( - new ApiException("readAuthorizationModel", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = readAuthorizationModelRequestBuilder(storeId, id, configuration) + .build(); + return new HttpRequestAttempt<>( + request, + "readAuthorizationModel", + ReadAuthorizationModelResponse.class, + apiClient, + configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1552,11 +1443,13 @@ private CompletableFuture> readAutho try { HttpRequest.Builder localVarRequestBuilder = readAuthorizationModelRequestBuilder(storeId, id, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture( @@ -1569,9 +1462,11 @@ private CompletableFuture> readAutho localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1615,8 +1510,8 @@ private HttpRequest.Builder readAuthorizationModelRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1657,27 +1552,16 @@ private CompletableFuture readAuthorizationMode String storeId, Integer pageSize, String continuationToken, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - readAuthorizationModelsRequestBuilder(storeId, pageSize, continuationToken, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture( - new ApiException("readAuthorizationModels", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = readAuthorizationModelsRequestBuilder( + storeId, pageSize, continuationToken, configuration) + .build(); + return new HttpRequestAttempt<>( + request, + "readAuthorizationModels", + ReadAuthorizationModelsResponse.class, + apiClient, + configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1721,11 +1605,13 @@ private CompletableFuture> readAuth try { HttpRequest.Builder localVarRequestBuilder = readAuthorizationModelsRequestBuilder(storeId, pageSize, continuationToken, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture( @@ -1738,9 +1624,11 @@ private CompletableFuture> readAuth localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1799,8 +1687,8 @@ private HttpRequest.Builder readAuthorizationModelsRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -1847,25 +1735,10 @@ private CompletableFuture readChanges( String storeId, String type, Integer pageSize, String continuationToken, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - readChangesRequestBuilder(storeId, type, pageSize, continuationToken, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("readChanges", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = readChangesRequestBuilder(storeId, type, pageSize, continuationToken, configuration) + .build(); + return new HttpRequestAttempt<>(request, "readChanges", ReadChangesResponse.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -1915,11 +1788,13 @@ private CompletableFuture> readChangesWithHttpI try { HttpRequest.Builder localVarRequestBuilder = readChangesRequestBuilder(storeId, type, pageSize, continuationToken, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("readChanges", localVarResponse)); @@ -1931,8 +1806,11 @@ private CompletableFuture> readChangesWithHttpI localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -1992,8 +1870,8 @@ private HttpRequest.Builder readChangesRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -2029,24 +1907,10 @@ public CompletableFuture write( private CompletableFuture write(String storeId, WriteRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = writeRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture(new ApiException("write", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = + writeRequestBuilder(storeId, body, configuration).build(); + return new HttpRequestAttempt<>(request, "write", Object.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -2085,11 +1949,13 @@ private CompletableFuture> writeWithHttpInfo( throws ApiException, FgaInvalidParameterException { try { HttpRequest.Builder localVarRequestBuilder = writeRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture(new ApiException("write", localVarResponse)); @@ -2101,8 +1967,9 @@ private CompletableFuture> writeWithHttpInfo( localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue(responseBody, new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -2141,7 +2008,7 @@ private HttpRequest.Builder writeRequestBuilder(String storeId, WriteRequest bod } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -2150,8 +2017,8 @@ private HttpRequest.Builder writeRequestBuilder(String storeId, WriteRequest bod if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -2194,17 +2061,10 @@ private CompletableFuture writeAssertions( String storeId, String authorizationModelId, WriteAssertionsRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - writeAssertionsRequestBuilder(storeId, authorizationModelId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture( - new ApiException("writeAssertions", localVarResponse)); - } - return CompletableFuture.completedFuture(null); - }); + HttpRequest request = writeAssertionsRequestBuilder(storeId, authorizationModelId, body, configuration) + .build(); + return new HttpRequestAttempt<>(request, "writeAssertions", Void.class, apiClient, configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -2251,11 +2111,13 @@ private CompletableFuture> writeAssertionsWithHttpInfo( try { HttpRequest.Builder localVarRequestBuilder = writeAssertionsRequestBuilder(storeId, authorizationModelId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture( @@ -2308,7 +2170,7 @@ private HttpRequest.Builder writeAssertionsRequestBuilder( } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("PUT", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -2317,8 +2179,8 @@ private HttpRequest.Builder writeAssertionsRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } @@ -2355,27 +2217,15 @@ private CompletableFuture writeAuthorizationMod String storeId, WriteAuthorizationModelRequest body, Configuration configuration) throws ApiException, FgaInvalidParameterException { try { - HttpRequest.Builder localVarRequestBuilder = - writeAuthorizationModelRequestBuilder(storeId, body, configuration); - return memberVarHttpClient - .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .thenComposeAsync(localVarResponse -> { - if (localVarResponse.statusCode() / 100 != 2) { - return CompletableFuture.failedFuture( - new ApiException("writeAuthorizationModel", localVarResponse)); - } - try { - String responseBody = localVarResponse.body(); - return CompletableFuture.completedFuture( - responseBody == null || responseBody.isBlank() - ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {})); - } catch (IOException e) { - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + HttpRequest request = writeAuthorizationModelRequestBuilder(storeId, body, configuration) + .build(); + return new HttpRequestAttempt<>( + request, + "writeAuthorizationModel", + WriteAuthorizationModelResponse.class, + apiClient, + configuration) + .attemptHttpRequest(); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } @@ -2415,11 +2265,13 @@ private CompletableFuture> writeAut try { HttpRequest.Builder localVarRequestBuilder = writeAuthorizationModelRequestBuilder(storeId, body, configuration); - return memberVarHttpClient + return apiClient + .getHttpClient() .sendAsync(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .thenComposeAsync(localVarResponse -> { - if (memberVarAsyncResponseInterceptor != null) { - memberVarAsyncResponseInterceptor.accept(localVarResponse); + var responseInterceptor = apiClient.getAsyncResponseInterceptor(); + if (responseInterceptor != null) { + responseInterceptor.accept(localVarResponse); } if (localVarResponse.statusCode() / 100 != 2) { return CompletableFuture.failedFuture( @@ -2432,9 +2284,11 @@ private CompletableFuture> writeAut localVarResponse.headers().map(), responseBody == null || responseBody.isBlank() ? null - : memberVarObjectMapper.readValue( - responseBody, - new TypeReference() {}))); + : apiClient + .getObjectMapper() + .readValue( + responseBody, + new TypeReference() {}))); } catch (IOException e) { return CompletableFuture.failedFuture(new ApiException(e)); } @@ -2476,7 +2330,7 @@ private HttpRequest.Builder writeAuthorizationModelRequestBuilder( } try { - byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(body); + byte[] localVarPostBody = apiClient.getObjectMapper().writeValueAsBytes(body); localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody)); } catch (IOException e) { throw new ApiException(e); @@ -2485,8 +2339,8 @@ private HttpRequest.Builder writeAuthorizationModelRequestBuilder( if (readTimeout != null) { localVarRequestBuilder.timeout(readTimeout); } - if (memberVarInterceptor != null) { - memberVarInterceptor.accept(localVarRequestBuilder); + if (apiClient.getRequestInterceptor() != null) { + apiClient.getRequestInterceptor().accept(localVarRequestBuilder); } return localVarRequestBuilder; } diff --git a/src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java b/src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java index 5c74533..118a3e2 100644 --- a/src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java +++ b/src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java @@ -12,23 +12,19 @@ package dev.openfga.sdk.api.auth; -import com.fasterxml.jackson.databind.ObjectMapper; import dev.openfga.sdk.api.client.ApiClient; +import dev.openfga.sdk.api.client.HttpRequestAttempt; import dev.openfga.sdk.api.configuration.*; import dev.openfga.sdk.errors.ApiException; import dev.openfga.sdk.errors.FgaInvalidParameterException; import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.http.HttpClient; import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.time.Instant; import java.util.concurrent.CompletableFuture; public class OAuth2Client { - private final HttpClient httpClient; + private final ApiClient apiClient; private final Credentials credentials; - private final ObjectMapper mapper; private final AccessToken token = new AccessToken(); private final CredentialsFlowRequest authRequest; private final String apiTokenIssuer; @@ -37,14 +33,11 @@ public class OAuth2Client { * Initializes a new instance of the {@link OAuth2Client} class * * @param configuration Configuration, including credentials, that can be used to retrieve an access tokens - * @param httpClient Http client */ - public OAuth2Client(Configuration configuration, HttpClient httpClient, ObjectMapper mapper) - throws FgaInvalidParameterException { + public OAuth2Client(Configuration configuration, ApiClient apiClient) throws FgaInvalidParameterException { this.credentials = configuration.getCredentials(); - this.httpClient = httpClient; - this.mapper = mapper; + this.apiClient = apiClient; this.apiTokenIssuer = credentials.getClientCredentials().getApiTokenIssuer(); this.authRequest = new CredentialsFlowRequest(); this.authRequest.setClientId(credentials.getClientCredentials().getClientId()); @@ -78,27 +71,15 @@ public CompletableFuture getAccessToken() throws FgaInvalidParameterExce private CompletableFuture exchangeToken() throws ApiException, FgaInvalidParameterException { try { - byte[] body = mapper.writeValueAsBytes(authRequest); + byte[] body = apiClient.getObjectMapper().writeValueAsBytes(authRequest); Configuration config = new Configuration().apiUrl("https://" + apiTokenIssuer); HttpRequest request = ApiClient.requestBuilder("POST", "/oauth/token", body, config) .build(); - return httpClient - .sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .thenCompose(httpResponse -> { - if (httpResponse.statusCode() != HttpURLConnection.HTTP_OK) { - return CompletableFuture.failedFuture(new ApiException("exchangeToken", httpResponse)); - } - try { - CredentialsFlowResponse response = - mapper.readValue(httpResponse.body(), CredentialsFlowResponse.class); - return CompletableFuture.completedFuture(response); - } catch (Exception e) { - return CompletableFuture.failedFuture(e); - } - }); + return new HttpRequestAttempt<>(request, "exchangeToken", CredentialsFlowResponse.class, apiClient, config) + .attemptHttpRequest(); } catch (IOException e) { throw new ApiException(e); } diff --git a/src/main/java/dev/openfga/sdk/api/client/ApiClient.java b/src/main/java/dev/openfga/sdk/api/client/ApiClient.java index 6901fae..89ae992 100644 --- a/src/main/java/dev/openfga/sdk/api/client/ApiClient.java +++ b/src/main/java/dev/openfga/sdk/api/client/ApiClient.java @@ -266,6 +266,17 @@ public HttpClient getHttpClient() { return builder.build(); } + /** + * Get the current {@link HttpClient.Builder}. + * + *

The returned object is immutable and thread-safe.

+ * + * @return The HTTP client. + */ + public HttpClient.Builder getHttpClientBuilder() { + return builder; + } + /** * Set a custom {@link ObjectMapper} to serialize and deserialize the request * and response bodies. diff --git a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java new file mode 100644 index 0000000..2985431 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java @@ -0,0 +1,114 @@ +package dev.openfga.sdk.api.client; + +import static dev.openfga.sdk.util.StringUtil.isNullOrWhitespace; + +import dev.openfga.sdk.api.configuration.BaseConfiguration; +import dev.openfga.sdk.errors.*; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.concurrent.*; + +public class HttpRequestAttempt { + private final ApiClient apiClient; + private final BaseConfiguration configuration; + private final Class clazz; + private final String name; + private final HttpRequest request; + + public HttpRequestAttempt( + HttpRequest request, String name, Class clazz, ApiClient apiClient, BaseConfiguration configuration) + throws FgaInvalidParameterException { + if (configuration.getMaxRetries() == null) { + throw new FgaInvalidParameterException("maxRetries", "Configuration"); + } + this.apiClient = apiClient; + this.configuration = configuration; + this.name = name; + this.request = request; + this.clazz = clazz; + } + + public CompletableFuture attemptHttpRequest() throws ApiException { + int retryNumber = 0; + return attemptHttpRequest(apiClient.getHttpClient(), retryNumber); + } + + private CompletableFuture attemptHttpRequest(HttpClient httpClient, int retryNumber) { + return httpClient + .sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenCompose(response -> { + int status = response.statusCode(); + String responseBody = response.body(); + + try { + checkStatus(name, response); + } catch (FgaApiRateLimitExceededError | FgaApiInternalError e) { + if (retryNumber < configuration.getMaxRetries()) { + HttpClient delayingClient = getDelayedHttpClient(); + return attemptHttpRequest(delayingClient, retryNumber + 1); + } + return CompletableFuture.failedFuture(e); + } catch (ApiException e) { + return CompletableFuture.failedFuture(e); + } + + if (status != HttpURLConnection.HTTP_OK + && status != HttpURLConnection.HTTP_CREATED + && status != HttpURLConnection.HTTP_NO_CONTENT) { + // An HTTP failure that is not modeled in checkStatus(..., ...) below. + return CompletableFuture.failedFuture(new ApiException(name, response)); + } + + if (clazz == Void.class && isNullOrWhitespace(responseBody)) { + return CompletableFuture.completedFuture(null); + } + + try { + T body = apiClient.getObjectMapper().readValue(responseBody, clazz); + return CompletableFuture.completedFuture(body); + } catch (IOException e) { + // Malformed response. + return CompletableFuture.failedFuture(new ApiException(e)); + } + }); + } + + private HttpClient getDelayedHttpClient() { + Duration retryDelay = configuration.getMinimumRetryDelay(); + return apiClient + .getHttpClientBuilder() + .executor(CompletableFuture.delayedExecutor(retryDelay.toNanos(), TimeUnit.NANOSECONDS)) + .build(); + } + + private static void checkStatus(String name, HttpResponse response) + throws FgaApiValidationError, FgaApiAuthenticationError, FgaApiNotFoundError, FgaApiRateLimitExceededError, + FgaApiInternalError { + + int status = response.statusCode(); + String body = response.body(); + + switch (status) { + case HttpURLConnection.HTTP_BAD_REQUEST: + case 422: // HTTP 422 Unprocessable Entity + throw new FgaApiValidationError(name, status, response.headers(), body); + + case HttpURLConnection.HTTP_UNAUTHORIZED: + case HttpURLConnection.HTTP_FORBIDDEN: + throw new FgaApiAuthenticationError(name, status, response.headers(), body); + + case HttpURLConnection.HTTP_NOT_FOUND: + throw new FgaApiNotFoundError(name, status, response.headers(), body); + + case 429: // HTTP 429 Too Many Requests + throw new FgaApiRateLimitExceededError(name, status, response.headers(), body); + + case HttpURLConnection.HTTP_INTERNAL_ERROR: + throw new FgaApiInternalError(name, status, response.headers(), body); + } + } +} diff --git a/src/main/java/dev/openfga/sdk/api/configuration/BaseConfiguration.java b/src/main/java/dev/openfga/sdk/api/configuration/BaseConfiguration.java index d69162b..d302294 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/BaseConfiguration.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/BaseConfiguration.java @@ -22,4 +22,8 @@ public interface BaseConfiguration { Duration getReadTimeout(); Duration getConnectTimeout(); + + Integer getMaxRetries(); + + Duration getMinimumRetryDelay(); } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientConfiguration.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientConfiguration.java index 5cd9bb5..3d10d0f 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientConfiguration.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientConfiguration.java @@ -132,4 +132,16 @@ public ClientConfiguration connectTimeout(Duration connectTimeout) { super.connectTimeout(connectTimeout); return this; } + + @Override + public ClientConfiguration maxRetries(int maxRetries) { + super.maxRetries(maxRetries); + return this; + } + + @Override + public ClientConfiguration minimumRetryDelay(Duration minimumRetryDelay) { + super.minimumRetryDelay(minimumRetryDelay); + return this; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/Configuration.java b/src/main/java/dev/openfga/sdk/api/configuration/Configuration.java index a45f915..82b6d99 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/Configuration.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/Configuration.java @@ -39,6 +39,8 @@ public class Configuration implements BaseConfiguration { private String userAgent; private Duration readTimeout; private Duration connectTimeout; + private int maxRetries; + private Duration minimumRetryDelay; public Configuration() { this.apiUrl = DEFAULT_API_URL; @@ -101,6 +103,12 @@ public Configuration override(ConfigurationOverride configurationOverride) { Duration overrideConnectTimeout = configurationOverride.getConnectTimeout(); result.connectTimeout(overrideConnectTimeout != null ? overrideConnectTimeout : connectTimeout); + Integer overrideMaxRetries = configurationOverride.getMaxRetries(); + result.maxRetries(overrideMaxRetries != null ? overrideMaxRetries : maxRetries); + + Duration overrideMinimumRetryDelay = configurationOverride.getMinimumRetryDelay(); + result.minimumRetryDelay(overrideMinimumRetryDelay != null ? overrideMinimumRetryDelay : minimumRetryDelay); + return result; } @@ -231,4 +239,24 @@ public Configuration connectTimeout(Duration connectTimeout) { public Duration getConnectTimeout() { return connectTimeout; } + + public Configuration maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + @Override + public Integer getMaxRetries() { + return maxRetries; + } + + public Configuration minimumRetryDelay(Duration minimumRetryDelay) { + this.minimumRetryDelay = minimumRetryDelay; + return this; + } + + @Override + public Duration getMinimumRetryDelay() { + return minimumRetryDelay; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ConfigurationOverride.java b/src/main/java/dev/openfga/sdk/api/configuration/ConfigurationOverride.java index d2b31dc..1d54a00 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ConfigurationOverride.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ConfigurationOverride.java @@ -29,6 +29,8 @@ public class ConfigurationOverride implements BaseConfiguration { private String userAgent; private Duration readTimeout; private Duration connectTimeout; + private Integer maxRetries; + private Duration minimumRetryDelay; public ConfigurationOverride() { this.apiUrl = null; @@ -157,4 +159,24 @@ public ConfigurationOverride connectTimeout(Duration connectTimeout) { public Duration getConnectTimeout() { return connectTimeout; } + + public ConfigurationOverride maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + @Override + public Integer getMaxRetries() { + return maxRetries; + } + + public ConfigurationOverride minimumRetryDelay(Duration minimumRetryDelay) { + this.minimumRetryDelay = minimumRetryDelay; + return this; + } + + @Override + public Duration getMinimumRetryDelay() { + return minimumRetryDelay; + } } diff --git a/src/main/java/dev/openfga/sdk/errors/FgaApiAuthenticationError.java b/src/main/java/dev/openfga/sdk/errors/FgaApiAuthenticationError.java new file mode 100644 index 0000000..14a4b2d --- /dev/null +++ b/src/main/java/dev/openfga/sdk/errors/FgaApiAuthenticationError.java @@ -0,0 +1,14 @@ +package dev.openfga.sdk.errors; + +import java.net.http.HttpHeaders; + +public class FgaApiAuthenticationError extends ApiException { + public FgaApiAuthenticationError( + String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, code, responseHeaders, responseBody); + } + + public FgaApiAuthenticationError(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } +} diff --git a/src/main/java/dev/openfga/sdk/errors/FgaApiInternalError.java b/src/main/java/dev/openfga/sdk/errors/FgaApiInternalError.java new file mode 100644 index 0000000..2ccf52c --- /dev/null +++ b/src/main/java/dev/openfga/sdk/errors/FgaApiInternalError.java @@ -0,0 +1,14 @@ +package dev.openfga.sdk.errors; + +import java.net.http.HttpHeaders; + +public class FgaApiInternalError extends ApiException { + public FgaApiInternalError( + String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, code, responseHeaders, responseBody); + } + + public FgaApiInternalError(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } +} diff --git a/src/main/java/dev/openfga/sdk/errors/FgaApiNotFoundError.java b/src/main/java/dev/openfga/sdk/errors/FgaApiNotFoundError.java new file mode 100644 index 0000000..5c395c9 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/errors/FgaApiNotFoundError.java @@ -0,0 +1,14 @@ +package dev.openfga.sdk.errors; + +import java.net.http.HttpHeaders; + +public class FgaApiNotFoundError extends ApiException { + public FgaApiNotFoundError( + String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, code, responseHeaders, responseBody); + } + + public FgaApiNotFoundError(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } +} diff --git a/src/main/java/dev/openfga/sdk/errors/FgaApiRateLimitExceededError.java b/src/main/java/dev/openfga/sdk/errors/FgaApiRateLimitExceededError.java new file mode 100644 index 0000000..73454b6 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/errors/FgaApiRateLimitExceededError.java @@ -0,0 +1,14 @@ +package dev.openfga.sdk.errors; + +import java.net.http.HttpHeaders; + +public class FgaApiRateLimitExceededError extends ApiException { + public FgaApiRateLimitExceededError( + String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, code, responseHeaders, responseBody); + } + + public FgaApiRateLimitExceededError(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } +} diff --git a/src/main/java/dev/openfga/sdk/errors/FgaApiValidationError.java b/src/main/java/dev/openfga/sdk/errors/FgaApiValidationError.java new file mode 100644 index 0000000..b915ab7 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/errors/FgaApiValidationError.java @@ -0,0 +1,14 @@ +package dev.openfga.sdk.errors; + +import java.net.http.HttpHeaders; + +public class FgaApiValidationError extends ApiException { + public FgaApiValidationError( + String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, code, responseHeaders, responseBody); + } + + public FgaApiValidationError(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } +} diff --git a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java index d47efb6..8e0e44c 100644 --- a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java +++ b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java @@ -22,6 +22,7 @@ import dev.openfga.sdk.api.configuration.*; import dev.openfga.sdk.api.model.*; import dev.openfga.sdk.errors.*; +import java.net.http.HttpClient; import java.time.Duration; import java.util.List; import java.util.concurrent.ExecutionException; @@ -40,26 +41,36 @@ public class OpenFgaApiTest { private static final String DEFAULT_TYPE = "document"; private static final String DEFAULT_OBJECT = "document:budget"; private static final String DEFAULT_SCHEMA_VERSION = "1.1"; - public static final String EMPTY_RESPONSE_BODY = "{}"; + private static final String EMPTY_RESPONSE_BODY = "{}"; + private static final int DEFAULT_MAX_RETRIES = 3; + private static final Duration DEFAULT_RETRY_DELAY = Duration.ofMillis(100); private final ObjectMapper mapper = new ObjectMapper(); private OpenFgaApi fga; private Configuration mockConfiguration; private ApiClient mockApiClient; private HttpClientMock mockHttpClient; + private HttpClient.Builder mockHttpClientBuilder; @BeforeEach public void beforeEachTest() throws Exception { mockHttpClient = new HttpClientMock(); + mockHttpClientBuilder = mock(HttpClient.Builder.class); + when(mockHttpClientBuilder.executor(any())).thenReturn(mockHttpClientBuilder); + when(mockHttpClientBuilder.build()).thenReturn(mockHttpClient); + mockConfiguration = mock(Configuration.class); when(mockConfiguration.getApiUrl()).thenReturn("https://localhost"); when(mockConfiguration.getReadTimeout()).thenReturn(Duration.ofMillis(250)); when(mockConfiguration.getCredentials()).thenReturn(new Credentials()); + when(mockConfiguration.getMaxRetries()).thenReturn(DEFAULT_MAX_RETRIES); + when(mockConfiguration.getMinimumRetryDelay()).thenReturn(DEFAULT_RETRY_DELAY); mockApiClient = mock(ApiClient.class); when(mockApiClient.getObjectMapper()).thenReturn(mapper); when(mockApiClient.getHttpClient()).thenReturn(mockHttpClient); + when(mockApiClient.getHttpClientBuilder()).thenReturn(mockHttpClientBuilder); fga = new OpenFgaApi(mockConfiguration, mockApiClient); } @@ -148,7 +159,7 @@ public void listStores_500() throws Exception { .get()); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1); + mockHttpClient.verify().get("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -247,7 +258,7 @@ public void createStore_500() throws Exception { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -338,7 +349,7 @@ public void getStore_500() throws Exception { ExecutionException.class, () -> fga.getStore(DEFAULT_STORE_ID).get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -429,7 +440,7 @@ public void deleteStore_500() throws Exception { .get()); // Then - mockHttpClient.verify().delete(deleteUrl).called(1); + mockHttpClient.verify().delete(deleteUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -541,7 +552,7 @@ public void readAuthorizationModels_500() throws Exception { .get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -656,7 +667,7 @@ DEFAULT_STORE_ID, new WriteAuthorizationModelRequest()) .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -772,7 +783,7 @@ public void readAuthorizationModel_500() throws Exception { .get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -887,7 +898,7 @@ public void readChanges_500() throws Exception { .get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1008,7 +1019,7 @@ public void read_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1148,7 +1159,7 @@ public void write_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1265,7 +1276,7 @@ public void check_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1393,7 +1404,7 @@ public void expand_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1509,7 +1520,7 @@ public void listObjects_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1627,7 +1638,7 @@ public void readAssertions_500() throws Exception { .get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1755,7 +1766,7 @@ DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID, new WriteAssertionsRequest()) .get()); // Then - mockHttpClient.verify().put(putUrl).called(1); + mockHttpClient.verify().put(putUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( diff --git a/src/test/java/dev/openfga/sdk/api/auth/OAuth2ClientTest.java b/src/test/java/dev/openfga/sdk/api/auth/OAuth2ClientTest.java index 8819c66..1a6a847 100644 --- a/src/test/java/dev/openfga/sdk/api/auth/OAuth2ClientTest.java +++ b/src/test/java/dev/openfga/sdk/api/auth/OAuth2ClientTest.java @@ -2,9 +2,12 @@ import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; import com.pgssoft.httpclient.HttpClientMock; +import dev.openfga.sdk.api.client.ApiClient; import dev.openfga.sdk.api.configuration.*; import dev.openfga.sdk.errors.FgaInvalidParameterException; import org.junit.jupiter.api.BeforeEach; @@ -36,7 +39,11 @@ public void setup() throws FgaInvalidParameterException { var configuration = new Configuration().apiUrl("").credentials(credentials); - oAuth2 = new OAuth2Client(configuration, mockHttpClient, mapper); + var apiClient = mock(ApiClient.class); + when(apiClient.getHttpClient()).thenReturn(mockHttpClient); + when(apiClient.getObjectMapper()).thenReturn(mapper); + + oAuth2 = new OAuth2Client(configuration, apiClient); } @Test diff --git a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java index ed83e90..50bb800 100644 --- a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java +++ b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java @@ -21,6 +21,7 @@ import dev.openfga.sdk.api.configuration.*; import dev.openfga.sdk.api.model.*; import dev.openfga.sdk.errors.*; +import java.net.http.HttpClient; import java.time.Duration; import java.util.List; import java.util.concurrent.ExecutionException; @@ -39,26 +40,36 @@ public class OpenFgaClientTest { private static final String DEFAULT_TYPE = "document"; private static final String DEFAULT_OBJECT = "document:budget"; private static final String DEFAULT_SCHEMA_VERSION = "1.1"; - public static final String EMPTY_RESPONSE_BODY = "{}"; + private static final String EMPTY_RESPONSE_BODY = "{}"; + private static final int DEFAULT_MAX_RETRIES = 3; + private static final Duration DEFAULT_RETRY_DELAY = Duration.ofMillis(100); private OpenFgaClient fga; private ClientConfiguration clientConfiguration; private HttpClientMock mockHttpClient; + private HttpClient.Builder mockHttpClientBuilder; @BeforeEach public void beforeEachTest() throws Exception { mockHttpClient = new HttpClientMock(); + mockHttpClientBuilder = mock(HttpClient.Builder.class); + when(mockHttpClientBuilder.executor(any())).thenReturn(mockHttpClientBuilder); + when(mockHttpClientBuilder.build()).thenReturn(mockHttpClient); + clientConfiguration = new ClientConfiguration() .storeId(DEFAULT_STORE_ID) .authorizationModelId(DEFAULT_AUTH_MODEL_ID) .apiUrl("https://localhost") .credentials(new Credentials()) - .readTimeout(Duration.ofMillis(250)); + .readTimeout(Duration.ofMillis(250)) + .maxRetries(DEFAULT_MAX_RETRIES) + .minimumRetryDelay(DEFAULT_RETRY_DELAY); ApiClient mockApiClient = mock(ApiClient.class); when(mockApiClient.getHttpClient()).thenReturn(mockHttpClient); when(mockApiClient.getObjectMapper()).thenReturn(new ObjectMapper()); + when(mockApiClient.getHttpClientBuilder()).thenReturn(mockHttpClientBuilder); fga = new OpenFgaClient(clientConfiguration, mockApiClient); } @@ -287,7 +298,7 @@ public void createStore_500() throws Exception { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -381,7 +392,7 @@ public void getStore_500() throws Exception { assertThrows(ExecutionException.class, () -> fga.getStore().get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -472,7 +483,7 @@ public void deleteStore_500() { assertThrows(ExecutionException.class, () -> fga.deleteStore().get()); // Then - mockHttpClient.verify().delete(deleteUrl).called(1); + mockHttpClient.verify().delete(deleteUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -580,7 +591,7 @@ public void readAuthorizationModels_500() throws Exception { .get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -751,7 +762,7 @@ public void writeAuthorizationModel_500() { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -891,7 +902,7 @@ public void readAuthorizationModel_500() throws Exception { ExecutionException.class, () -> fga.readAuthorizationModel().get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1002,7 +1013,7 @@ public void read_500() { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1168,7 +1179,7 @@ public void write_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1271,7 +1282,7 @@ public void check_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1389,7 +1400,7 @@ public void expand_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1493,7 +1504,7 @@ public void listObjects_500() throws Exception { .get()); // Then - mockHttpClient.verify().post(postUrl).called(1); + mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1614,7 +1625,7 @@ public void readAssertions_500() throws Exception { ExecutionException.class, () -> fga.readAssertions().get()); // Then - mockHttpClient.verify().get(getUrl).called(1); + mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( @@ -1732,7 +1743,7 @@ public void writeAssertions_500() throws Exception { ExecutionException.class, () -> fga.writeAssertions(List.of()).get()); // Then - mockHttpClient.verify().put(putUrl).called(1); + mockHttpClient.verify().put(putUrl).called(1 + DEFAULT_MAX_RETRIES); ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( From 08392cb50c4544865f4b0be0d3aa2e8b697d99eb Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Wed, 4 Oct 2023 10:06:32 -0700 Subject: [PATCH 2/4] refactor: refactor http request attempts --- .../sdk/api/client/HttpRequestAttempt.java | 62 ++++++++----------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java index 2985431..3a9348b 100644 --- a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java +++ b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java @@ -34,47 +34,41 @@ public HttpRequestAttempt( public CompletableFuture attemptHttpRequest() throws ApiException { int retryNumber = 0; - return attemptHttpRequest(apiClient.getHttpClient(), retryNumber); + return attemptHttpRequest(apiClient.getHttpClient(), retryNumber, null); } - private CompletableFuture attemptHttpRequest(HttpClient httpClient, int retryNumber) { + private CompletableFuture attemptHttpRequest(HttpClient httpClient, int retryNumber, Throwable previousError) { return httpClient .sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenCompose(response -> { - int status = response.statusCode(); - String responseBody = response.body(); - try { - checkStatus(name, response); - } catch (FgaApiRateLimitExceededError | FgaApiInternalError e) { + checkStatus(name, response, previousError); + } catch (FgaApiRateLimitExceededError | FgaApiInternalError retryableError) { if (retryNumber < configuration.getMaxRetries()) { HttpClient delayingClient = getDelayedHttpClient(); - return attemptHttpRequest(delayingClient, retryNumber + 1); + return attemptHttpRequest(delayingClient, retryNumber + 1, retryableError); } - return CompletableFuture.failedFuture(e); + return CompletableFuture.failedFuture(retryableError); } catch (ApiException e) { return CompletableFuture.failedFuture(e); } - if (status != HttpURLConnection.HTTP_OK - && status != HttpURLConnection.HTTP_CREATED - && status != HttpURLConnection.HTTP_NO_CONTENT) { - // An HTTP failure that is not modeled in checkStatus(..., ...) below. - return CompletableFuture.failedFuture(new ApiException(name, response)); - } + return deserializeResponse(response); + }); + } - if (clazz == Void.class && isNullOrWhitespace(responseBody)) { - return CompletableFuture.completedFuture(null); - } + private CompletableFuture deserializeResponse(HttpResponse response) { + if (clazz == Void.class && isNullOrWhitespace(response.body())) { + return CompletableFuture.completedFuture(null); + } - try { - T body = apiClient.getObjectMapper().readValue(responseBody, clazz); - return CompletableFuture.completedFuture(body); - } catch (IOException e) { - // Malformed response. - return CompletableFuture.failedFuture(new ApiException(e)); - } - }); + try { + T deserialized = apiClient.getObjectMapper().readValue(response.body(), clazz); + return CompletableFuture.completedFuture(deserialized); + } catch (IOException e) { + // Malformed response. + return CompletableFuture.failedFuture(new ApiException(e)); + } } private HttpClient getDelayedHttpClient() { @@ -85,30 +79,28 @@ private HttpClient getDelayedHttpClient() { .build(); } - private static void checkStatus(String name, HttpResponse response) - throws FgaApiValidationError, FgaApiAuthenticationError, FgaApiNotFoundError, FgaApiRateLimitExceededError, - FgaApiInternalError { - + private static void checkStatus(String name, HttpResponse response, Throwable previousError) + throws ApiException { int status = response.statusCode(); String body = response.body(); switch (status) { case HttpURLConnection.HTTP_BAD_REQUEST: case 422: // HTTP 422 Unprocessable Entity - throw new FgaApiValidationError(name, status, response.headers(), body); + throw new FgaApiValidationError(name, previousError, status, response.headers(), body); case HttpURLConnection.HTTP_UNAUTHORIZED: case HttpURLConnection.HTTP_FORBIDDEN: - throw new FgaApiAuthenticationError(name, status, response.headers(), body); + throw new FgaApiAuthenticationError(name, previousError, status, response.headers(), body); case HttpURLConnection.HTTP_NOT_FOUND: - throw new FgaApiNotFoundError(name, status, response.headers(), body); + throw new FgaApiNotFoundError(name, previousError, status, response.headers(), body); case 429: // HTTP 429 Too Many Requests - throw new FgaApiRateLimitExceededError(name, status, response.headers(), body); + throw new FgaApiRateLimitExceededError(name, previousError, status, response.headers(), body); case HttpURLConnection.HTTP_INTERNAL_ERROR: - throw new FgaApiInternalError(name, status, response.headers(), body); + throw new FgaApiInternalError(name, previousError, status, response.headers(), body); } } } From 8d43b08bd18fb855136e972fd3d30370ca6dc410 Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Thu, 5 Oct 2023 12:09:44 -0700 Subject: [PATCH 3/4] test: use more specific exception types in tests --- .../dev/openfga/sdk/api/OpenFgaApiTest.java | 138 +++++++++--------- .../sdk/api/client/OpenFgaClientTest.java | 82 +++++------ 2 files changed, 110 insertions(+), 110 deletions(-) diff --git a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java index 8e0e44c..4572fc0 100644 --- a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java +++ b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java @@ -115,7 +115,7 @@ public void listStores_400() { // Then mockHttpClient.verify().get("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -138,7 +138,7 @@ public void listStores_404() throws Exception { // Then mockHttpClient.verify().get("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -160,7 +160,7 @@ public void listStores_500() throws Exception { // Then mockHttpClient.verify().get("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -200,7 +200,7 @@ public void createStore_bodyRequired() { ExecutionException.class, () -> fga.createStore(null).get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling createStore", exception.getMessage()); } @@ -218,7 +218,7 @@ public void createStore_400() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -239,7 +239,7 @@ public void createStore_404() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -259,7 +259,7 @@ public void createStore_500() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -291,7 +291,7 @@ public void getStore_storeIdRequired() { assertThrows(ExecutionException.class, () -> fga.getStore(null).get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling getStore", exception.getMessage()); } @@ -309,7 +309,7 @@ public void getStore_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -330,7 +330,7 @@ public void getStore_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -350,7 +350,7 @@ public void getStore_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -379,7 +379,7 @@ public void deleteStore_storeIdRequired() { ExecutionException.class, () -> fga.deleteStore(null).get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling deleteStore", exception.getMessage()); } @@ -398,7 +398,7 @@ public void deleteStore_400() throws Exception { // Then mockHttpClient.verify().delete(deleteUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -420,7 +420,7 @@ public void deleteStore_404() throws Exception { // Then mockHttpClient.verify().delete(deleteUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -441,7 +441,7 @@ public void deleteStore_500() throws Exception { // Then mockHttpClient.verify().delete(deleteUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -483,7 +483,7 @@ public void readAuthorizationModels_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'storeId' when calling readAuthorizationModels", exception.getMessage()); @@ -506,7 +506,7 @@ public void readAuthorizationModels_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -530,7 +530,7 @@ public void readAuthorizationModels_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -553,7 +553,7 @@ public void readAuthorizationModels_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -591,7 +591,7 @@ public void writeAuthorizationModel_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'storeId' when calling writeAuthorizationModel", exception.getMessage()); @@ -605,7 +605,7 @@ public void writeAuthorizationModel_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'body' when calling writeAuthorizationModel", exception.getMessage()); } @@ -625,7 +625,7 @@ DEFAULT_STORE_ID, new WriteAuthorizationModelRequest()) // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -647,7 +647,7 @@ DEFAULT_STORE_ID, new WriteAuthorizationModelRequest()) // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -668,7 +668,7 @@ DEFAULT_STORE_ID, new WriteAuthorizationModelRequest()) // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -706,7 +706,7 @@ public void readAuthorizationModel_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'storeId' when calling readAuthorizationModel", exception.getMessage()); } @@ -719,7 +719,7 @@ public void readAuthorizationModel_idRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'id' when calling readAuthorizationModel", exception.getMessage()); } @@ -739,7 +739,7 @@ public void readAuthorizationModel_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -762,7 +762,7 @@ public void readAuthorizationModel_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -784,7 +784,7 @@ public void readAuthorizationModel_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -828,7 +828,7 @@ public void readChanges_storeIdRequired() throws Exception { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling readChanges", exception.getMessage()); } @@ -850,7 +850,7 @@ public void readChanges_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -875,7 +875,7 @@ public void readChanges_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -899,7 +899,7 @@ public void readChanges_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -947,7 +947,7 @@ public void read_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling read", exception.getMessage()); } @@ -958,7 +958,7 @@ public void read_bodyRequired() { ExecutionException.class, () -> fga.read(DEFAULT_STORE_ID, null).get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling read", exception.getMessage()); } @@ -977,7 +977,7 @@ public void read_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -999,7 +999,7 @@ public void read_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1020,7 +1020,7 @@ public void read_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1086,7 +1086,7 @@ public void write_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling write", exception.getMessage()); } @@ -1098,7 +1098,7 @@ public void write_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling write", exception.getMessage()); } @@ -1117,7 +1117,7 @@ public void write_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1139,7 +1139,7 @@ public void write_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1160,7 +1160,7 @@ public void write_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1203,7 +1203,7 @@ public void check_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling check", exception.getMessage()); } @@ -1215,7 +1215,7 @@ public void check_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling check", exception.getMessage()); } @@ -1234,7 +1234,7 @@ public void check_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1256,7 +1256,7 @@ public void check_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1277,7 +1277,7 @@ public void check_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1331,7 +1331,7 @@ public void expand_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling expand", exception.getMessage()); } @@ -1343,7 +1343,7 @@ public void expand_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling expand", exception.getMessage()); } @@ -1362,7 +1362,7 @@ public void expand_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1384,7 +1384,7 @@ public void expand_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1405,7 +1405,7 @@ public void expand_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1447,7 +1447,7 @@ public void listObjects_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling listObjects", exception.getMessage()); } @@ -1459,7 +1459,7 @@ public void listObjects_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling listObjects", exception.getMessage()); } @@ -1478,7 +1478,7 @@ public void listObjects_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1500,7 +1500,7 @@ public void listObjects_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1521,7 +1521,7 @@ public void listObjects_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1563,7 +1563,7 @@ public void readAssertions_storeIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling readAssertions", exception.getMessage()); } @@ -1575,7 +1575,7 @@ public void readAssertions_authModelIdRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'authorizationModelId' when calling readAssertions", exception.getMessage()); @@ -1596,7 +1596,7 @@ public void readAssertions_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1618,7 +1618,7 @@ public void readAssertions_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1639,7 +1639,7 @@ public void readAssertions_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1679,7 +1679,7 @@ null, DEFAULT_AUTH_MODEL_ID, new WriteAssertionsRequest()) .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'storeId' when calling writeAssertions", exception.getMessage()); } @@ -1691,7 +1691,7 @@ DEFAULT_STORE_ID, null, new WriteAssertionsRequest()) .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'authorizationModelId' when calling writeAssertions", exception.getMessage()); @@ -1705,7 +1705,7 @@ public void writeAssertions_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling writeAssertions", exception.getMessage()); } @@ -1724,7 +1724,7 @@ DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID, new WriteAssertionsRequest()) // Then mockHttpClient.verify().put(putUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1746,7 +1746,7 @@ DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID, new WriteAssertionsRequest()) // Then mockHttpClient.verify().put(putUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1767,7 +1767,7 @@ DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID, new WriteAssertionsRequest()) // Then mockHttpClient.verify().put(putUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); diff --git a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java index 50bb800..3747da9 100644 --- a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java +++ b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java @@ -240,7 +240,7 @@ public void createStore_bodyRequired() { ExecutionException.class, () -> fga.createStore(null).get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals("Missing the required parameter 'body' when calling createStore", exception.getMessage()); } @@ -258,7 +258,7 @@ public void createStore_400() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -279,7 +279,7 @@ public void createStore_404() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -299,7 +299,7 @@ public void createStore_500() throws Exception { // Then mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -352,7 +352,7 @@ public void getStore_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -373,7 +373,7 @@ public void getStore_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -393,7 +393,7 @@ public void getStore_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -443,7 +443,7 @@ public void deleteStore_400() { // Then mockHttpClient.verify().delete(deleteUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -464,7 +464,7 @@ public void deleteStore_404() { // Then mockHttpClient.verify().delete(deleteUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -484,7 +484,7 @@ public void deleteStore_500() { // Then mockHttpClient.verify().delete(deleteUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -547,7 +547,7 @@ public void readAuthorizationModels_400() { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -570,7 +570,7 @@ public void readAuthorizationModels_404() { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -592,7 +592,7 @@ public void readAuthorizationModels_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -700,7 +700,7 @@ public void writeAuthorizationModel_bodyRequired() { .get()); // Then - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(ApiException.class, execException.getCause()); assertEquals( "Missing the required parameter 'body' when calling writeAuthorizationModel", exception.getMessage()); } @@ -720,7 +720,7 @@ public void writeAuthorizationModel_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -742,7 +742,7 @@ public void writeAuthorizationModel_404() { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -763,7 +763,7 @@ public void writeAuthorizationModel_500() { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -860,7 +860,7 @@ public void readAuthorizationModel_400() { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -882,7 +882,7 @@ public void readAuthorizationModel_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -903,7 +903,7 @@ public void readAuthorizationModel_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -971,7 +971,7 @@ public void read_400() { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -993,7 +993,7 @@ public void read_404() { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1014,7 +1014,7 @@ public void read_500() { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1137,7 +1137,7 @@ public void write_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1159,7 +1159,7 @@ public void write_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1180,7 +1180,7 @@ public void write_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1240,7 +1240,7 @@ public void check_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1262,7 +1262,7 @@ public void check_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1283,7 +1283,7 @@ public void check_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1358,7 +1358,7 @@ public void expand_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1380,7 +1380,7 @@ public void expand_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1401,7 +1401,7 @@ public void expand_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1462,7 +1462,7 @@ public void listObjects_400() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1484,7 +1484,7 @@ public void listObjects_404() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1505,7 +1505,7 @@ public void listObjects_500() throws Exception { // Then mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1583,7 +1583,7 @@ public void readAssertions_400() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1605,7 +1605,7 @@ public void readAssertions_404() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1626,7 +1626,7 @@ public void readAssertions_500() throws Exception { // Then mockHttpClient.verify().get(getUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); @@ -1701,7 +1701,7 @@ public void writeAssertions_400() throws Exception { // Then mockHttpClient.verify().put(putUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getCode()); assertEquals( "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}", @@ -1723,7 +1723,7 @@ public void writeAssertions_404() throws Exception { // Then mockHttpClient.verify().put(putUrl).called(1); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getCode()); assertEquals( "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseBody()); @@ -1744,7 +1744,7 @@ public void writeAssertions_500() throws Exception { // Then mockHttpClient.verify().put(putUrl).called(1 + DEFAULT_MAX_RETRIES); - ApiException exception = assertInstanceOf(ApiException.class, execException.getCause()); + var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getCode()); assertEquals( "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseBody()); From a84a576f9800c9d65faa81de0188a34019173a33 Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Thu, 5 Oct 2023 13:19:54 -0700 Subject: [PATCH 4/4] feat: treat non HTTP 2xx responses as exceptional --- .../java/dev/openfga/sdk/api/client/HttpRequestAttempt.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java index 3a9348b..9372948 100644 --- a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java +++ b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java @@ -102,5 +102,10 @@ private static void checkStatus(String name, HttpResponse response, Thro case HttpURLConnection.HTTP_INTERNAL_ERROR: throw new FgaApiInternalError(name, previousError, status, response.headers(), body); } + + // FGA and OAuth2 servers are only expected to return HTTP 2xx responses. + if (status < 200 || 300 <= status) { + throw new ApiException(name, previousError, status, response.headers(), body); + } } }