diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 683c204..d7553db 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -29,6 +29,7 @@ docs/Computed.md docs/Condition.md docs/ConditionMetadata.md docs/ConditionParamTypeRef.md +docs/ConsistencyPreference.md docs/ContextualTupleKeys.md docs/CreateStoreRequest.md docs/CreateStoreResponse.md @@ -199,6 +200,7 @@ src/main/java/dev/openfga/sdk/api/model/Computed.java src/main/java/dev/openfga/sdk/api/model/Condition.java src/main/java/dev/openfga/sdk/api/model/ConditionMetadata.java src/main/java/dev/openfga/sdk/api/model/ConditionParamTypeRef.java +src/main/java/dev/openfga/sdk/api/model/ConsistencyPreference.java src/main/java/dev/openfga/sdk/api/model/ContextualTupleKeys.java src/main/java/dev/openfga/sdk/api/model/CreateStoreRequest.java src/main/java/dev/openfga/sdk/api/model/CreateStoreResponse.java diff --git a/README.md b/README.md index 7bea246..341fde5 100644 --- a/README.md +++ b/README.md @@ -888,7 +888,7 @@ public class Example { | [**getStore**](docs/OpenFgaApi.md#getstore) | **GET** /stores/{store_id} | Get a store | | [**listObjects**](docs/OpenFgaApi.md#listobjects) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with | | [**listStores**](docs/OpenFgaApi.md#liststores) | **GET** /stores | List all stores | -| [**listUsers**](docs/OpenFgaApi.md#listusers) | **POST** /stores/{store_id}/list-users | [EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. | +| [**listUsers**](docs/OpenFgaApi.md#listusers) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | | [**read**](docs/OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readAssertions**](docs/OpenFgaApi.md#readassertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID | | [**readAuthorizationModel**](docs/OpenFgaApi.md#readauthorizationmodel) | **GET** /stores/{store_id}/authorization-models/{id} | Return a particular version of an authorization model | @@ -927,6 +927,8 @@ public class Example { - [ConditionParamTypeRef](https://github.com/openfga/java-sdk/blob/main/docs/ConditionParamTypeRef.md) +- [ConsistencyPreference](https://github.com/openfga/java-sdk/blob/main/docs/ConsistencyPreference.md) + - [ContextualTupleKeys](https://github.com/openfga/java-sdk/blob/main/docs/ContextualTupleKeys.md) - [CreateStoreRequest](https://github.com/openfga/java-sdk/blob/main/docs/CreateStoreRequest.md) diff --git a/docs/CheckRequest.md b/docs/CheckRequest.md index af3428a..d1873f9 100644 --- a/docs/CheckRequest.md +++ b/docs/CheckRequest.md @@ -12,6 +12,7 @@ |**authorizationModelId** | **String** | | [optional] | |**trace** | **Boolean** | Defaults to false. Making it true has performance implications. | [optional] [readonly] | |**context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] | +|**consistency** | **ConsistencyPreference** | | [optional] | diff --git a/docs/ConsistencyPreference.md b/docs/ConsistencyPreference.md new file mode 100644 index 0000000..309e3be --- /dev/null +++ b/docs/ConsistencyPreference.md @@ -0,0 +1,17 @@ + + +# ConsistencyPreference + +## Enum + + +* `UNSPECIFIED` (value: `"UNSPECIFIED"`) + +* `MINIMIZE_LATENCY` (value: `"MINIMIZE_LATENCY"`) + +* `HIGHER_CONSISTENCY` (value: `"HIGHER_CONSISTENCY"`) + +* `UNKNOWN_DEFAULT_OPEN_API` (value: `"unknown_default_open_api"`) + + + diff --git a/docs/ExpandRequest.md b/docs/ExpandRequest.md index 347ca0c..91ddc2e 100644 --- a/docs/ExpandRequest.md +++ b/docs/ExpandRequest.md @@ -9,6 +9,7 @@ |------------ | ------------- | ------------- | -------------| |**tupleKey** | [**ExpandRequestTupleKey**](ExpandRequestTupleKey.md) | | | |**authorizationModelId** | **String** | | [optional] | +|**consistency** | **ConsistencyPreference** | | [optional] | diff --git a/docs/ListObjectsRequest.md b/docs/ListObjectsRequest.md index 142f84a..be8c7fd 100644 --- a/docs/ListObjectsRequest.md +++ b/docs/ListObjectsRequest.md @@ -13,6 +13,7 @@ |**user** | **String** | | | |**contextualTuples** | [**ContextualTupleKeys**](ContextualTupleKeys.md) | | [optional] | |**context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] | +|**consistency** | **ConsistencyPreference** | | [optional] | diff --git a/docs/ListUsersRequest.md b/docs/ListUsersRequest.md index 2350bfd..89bc67c 100644 --- a/docs/ListUsersRequest.md +++ b/docs/ListUsersRequest.md @@ -13,6 +13,7 @@ |**userFilters** | [**List<UserTypeFilter>**](UserTypeFilter.md) | The type of results returned. Only accepts exactly one value. | | |**contextualTuples** | [**List<TupleKey>**](TupleKey.md) | | [optional] | |**context** | **Object** | Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. | [optional] | +|**consistency** | **ConsistencyPreference** | | [optional] | diff --git a/docs/OpenFgaApi.md b/docs/OpenFgaApi.md index 4fc19af..efefe55 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -18,8 +18,8 @@ All URIs are relative to *http://localhost* | [**listObjectsWithHttpInfo**](OpenFgaApi.md#listObjectsWithHttpInfo) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with | | [**listStores**](OpenFgaApi.md#listStores) | **GET** /stores | List all stores | | [**listStoresWithHttpInfo**](OpenFgaApi.md#listStoresWithHttpInfo) | **GET** /stores | List all stores | -| [**listUsers**](OpenFgaApi.md#listUsers) | **POST** /stores/{store_id}/list-users | [EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. | -| [**listUsersWithHttpInfo**](OpenFgaApi.md#listUsersWithHttpInfo) | **POST** /stores/{store_id}/list-users | [EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. | +| [**listUsers**](OpenFgaApi.md#listUsers) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | +| [**listUsersWithHttpInfo**](OpenFgaApi.md#listUsersWithHttpInfo) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. | | [**read**](OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readWithHttpInfo**](OpenFgaApi.md#readWithHttpInfo) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules | | [**readAssertions**](OpenFgaApi.md#readAssertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID | @@ -1142,9 +1142,9 @@ No authorization required > CompletableFuture listUsers(storeId, body) -[EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. +List the users matching the provided filter who have a certain relation to a particular type. -The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. +The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. ### Example @@ -1216,9 +1216,9 @@ No authorization required > CompletableFuture> listUsers listUsersWithHttpInfo(storeId, body) -[EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. +List the users matching the provided filter who have a certain relation to a particular type. -The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. +The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. ### Example diff --git a/docs/ReadRequest.md b/docs/ReadRequest.md index 832f57c..88f2a9f 100644 --- a/docs/ReadRequest.md +++ b/docs/ReadRequest.md @@ -10,6 +10,7 @@ |**tupleKey** | [**ReadRequestTupleKey**](ReadRequestTupleKey.md) | | [optional] | |**pageSize** | **Integer** | | [optional] | |**continuationToken** | **String** | | [optional] | +|**consistency** | **ConsistencyPreference** | | [optional] | diff --git a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java index ea40ec5..b25ec67 100644 --- a/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java +++ b/src/main/java/dev/openfga/sdk/api/OpenFgaApi.java @@ -457,8 +457,8 @@ private CompletableFuture> listStores( } /** - * [EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * List the users matching the provided filter who have a certain relation to a particular type. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @param storeId (required) * @param body (required) * @return CompletableFuture<ApiResponse<ListUsersResponse>> @@ -470,8 +470,8 @@ public CompletableFuture> listUsers(String storeI } /** - * [EXPERIMENTAL] List the users matching the provided filter who have a certain relation to a particular type. - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. This API is available in an experimental capacity and can be enabled with the `--experimentals enable-list-users` flag. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * List the users matching the provided filter who have a certain relation to a particular type. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @param storeId (required) * @param body (required) * @param configurationOverride Override the {@link Configuration} this OpenFgaApi was constructed with diff --git a/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java b/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java index 3f357f0..77cf1d9 100644 --- a/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java +++ b/src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java @@ -329,6 +329,9 @@ public CompletableFuture read(ClientReadRequest request, Cli if (options != null) { body.pageSize(options.getPageSize()).continuationToken(options.getContinuationToken()); + if (options.getConsistency() != null) { + body.consistency(options.getConsistency()); + } } var overrides = new ConfigurationOverride().addHeaders(options); @@ -542,12 +545,18 @@ public CompletableFuture check(ClientCheckRequest request, String storeId = configuration.getStoreIdChecked(); CheckRequest body = request.asCheckRequest(); + if (options != null) { + if (options.getConsistency() != null) { + body.consistency(options.getConsistency()); + } - if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) { - body.authorizationModelId(options.getAuthorizationModelId()); - } else { - String authorizationModelId = configuration.getAuthorizationModelId(); + // Set authorizationModelId from options if available; otherwise, use the default from configuration + String authorizationModelId = !isNullOrWhitespace(options.getAuthorizationModelId()) + ? options.getAuthorizationModelId() + : configuration.getAuthorizationModelId(); body.authorizationModelId(authorizationModelId); + } else { + body.setAuthorizationModelId(configuration.getAuthorizationModelId()); } var overrides = new ConfigurationOverride().addHeaders(options); @@ -638,11 +647,18 @@ public CompletableFuture expand(ClientExpandRequest reques new ExpandRequestTupleKey().relation(request.getRelation())._object(request.getObject())); } - if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) { - body.authorizationModelId(options.getAuthorizationModelId()); - } else { - String authorizationModelId = configuration.getAuthorizationModelId(); + if (options != null) { + if (options.getConsistency() != null) { + body.consistency(options.getConsistency()); + } + + // Set authorizationModelId from options if available; otherwise, use the default from configuration + String authorizationModelId = !isNullOrWhitespace(options.getAuthorizationModelId()) + ? options.getAuthorizationModelId() + : configuration.getAuthorizationModelId(); body.authorizationModelId(authorizationModelId); + } else { + body.setAuthorizationModelId(configuration.getAuthorizationModelId()); } var overrides = new ConfigurationOverride().addHeaders(options); @@ -684,11 +700,18 @@ public CompletableFuture listObjects( } } - if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) { - body.authorizationModelId(options.getAuthorizationModelId()); - } else { - String authorizationModelId = configuration.getAuthorizationModelId(); + if (options != null) { + if (options.getConsistency() != null) { + body.consistency(options.getConsistency()); + } + + // Set authorizationModelId from options if available; otherwise, use the default from configuration + String authorizationModelId = !isNullOrWhitespace(options.getAuthorizationModelId()) + ? options.getAuthorizationModelId() + : configuration.getAuthorizationModelId(); body.authorizationModelId(authorizationModelId); + } else { + body.setAuthorizationModelId(configuration.getAuthorizationModelId()); } var overrides = new ConfigurationOverride().addHeaders(options); @@ -768,11 +791,18 @@ public CompletableFuture listUsers( } } - if (options != null && !isNullOrWhitespace(options.getAuthorizationModelId())) { - body.authorizationModelId(options.getAuthorizationModelId()); - } else { - String authorizationModelId = configuration.getAuthorizationModelId(); + if (options != null) { + if (options.getConsistency() != null) { + body.consistency(options.getConsistency()); + } + + // Set authorizationModelId from options if available; otherwise, use the default from configuration + String authorizationModelId = !isNullOrWhitespace(options.getAuthorizationModelId()) + ? options.getAuthorizationModelId() + : configuration.getAuthorizationModelId(); body.authorizationModelId(authorizationModelId); + } else { + body.setAuthorizationModelId(configuration.getAuthorizationModelId()); } var overrides = new ConfigurationOverride().addHeaders(options); diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientBatchCheckOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientBatchCheckOptions.java index b86e983..1a706a4 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientBatchCheckOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientBatchCheckOptions.java @@ -12,12 +12,14 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientBatchCheckOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private Integer maxParallelRequests; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientBatchCheckOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -47,7 +49,19 @@ public String getAuthorizationModelId() { return authorizationModelId; } + public ClientBatchCheckOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } + public ClientCheckOptions asClientCheckOptions() { - return new ClientCheckOptions().additionalHeaders(additionalHeaders).authorizationModelId(authorizationModelId); + return new ClientCheckOptions() + .additionalHeaders(additionalHeaders) + .authorizationModelId(authorizationModelId) + .consistency(consistency); } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientCheckOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientCheckOptions.java index 3820241..b50a9e8 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientCheckOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientCheckOptions.java @@ -12,11 +12,13 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientCheckOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientCheckOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -36,4 +38,13 @@ public ClientCheckOptions authorizationModelId(String authorizationModelId) { public String getAuthorizationModelId() { return authorizationModelId; } + + public ClientCheckOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientExpandOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientExpandOptions.java index ef1448d..8b40e8c 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientExpandOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientExpandOptions.java @@ -12,11 +12,13 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientExpandOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientExpandOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -36,4 +38,13 @@ public ClientExpandOptions authorizationModelId(String authorizationModelId) { public String getAuthorizationModelId() { return authorizationModelId; } + + public ClientExpandOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientListObjectsOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientListObjectsOptions.java index 4ac1615..b24b80c 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientListObjectsOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientListObjectsOptions.java @@ -12,11 +12,13 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientListObjectsOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientListObjectsOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -36,4 +38,13 @@ public ClientListObjectsOptions authorizationModelId(String authorizationModelId public String getAuthorizationModelId() { return authorizationModelId; } + + public ClientListObjectsOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientListRelationsOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientListRelationsOptions.java index 3abde9d..0ae80e5 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientListRelationsOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientListRelationsOptions.java @@ -12,12 +12,14 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientListRelationsOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private Integer maxParallelRequests; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientListRelationsOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -47,9 +49,19 @@ public String getAuthorizationModelId() { return authorizationModelId; } + public ClientListRelationsOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } + public ClientBatchCheckOptions asClientBatchCheckOptions() { return new ClientBatchCheckOptions() .authorizationModelId(authorizationModelId) - .maxParallelRequests(maxParallelRequests); + .maxParallelRequests(maxParallelRequests) + .consistency(consistency); } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java index 51783d6..9017b90 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientListUsersOptions.java @@ -12,11 +12,13 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientListUsersOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private String authorizationModelId; + private ConsistencyPreference consistency; public ClientListUsersOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -36,4 +38,13 @@ public ClientListUsersOptions authorizationModelId(String authorizationModelId) public String getAuthorizationModelId() { return authorizationModelId; } + + public ClientListUsersOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } } diff --git a/src/main/java/dev/openfga/sdk/api/configuration/ClientReadOptions.java b/src/main/java/dev/openfga/sdk/api/configuration/ClientReadOptions.java index b13cb44..cfa880c 100644 --- a/src/main/java/dev/openfga/sdk/api/configuration/ClientReadOptions.java +++ b/src/main/java/dev/openfga/sdk/api/configuration/ClientReadOptions.java @@ -12,12 +12,14 @@ package dev.openfga.sdk.api.configuration; +import dev.openfga.sdk.api.model.ConsistencyPreference; import java.util.Map; public class ClientReadOptions implements AdditionalHeadersSupplier { private Map additionalHeaders; private Integer pageSize; private String continuationToken; + private ConsistencyPreference consistency; public ClientReadOptions additionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; @@ -46,4 +48,13 @@ public ClientReadOptions continuationToken(String continuationToken) { public String getContinuationToken() { return continuationToken; } + + public ClientReadOptions consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + public ConsistencyPreference getConsistency() { + return consistency; + } } diff --git a/src/main/java/dev/openfga/sdk/api/model/CheckRequest.java b/src/main/java/dev/openfga/sdk/api/model/CheckRequest.java index a09c150..cccba86 100644 --- a/src/main/java/dev/openfga/sdk/api/model/CheckRequest.java +++ b/src/main/java/dev/openfga/sdk/api/model/CheckRequest.java @@ -29,7 +29,8 @@ CheckRequest.JSON_PROPERTY_CONTEXTUAL_TUPLES, CheckRequest.JSON_PROPERTY_AUTHORIZATION_MODEL_ID, CheckRequest.JSON_PROPERTY_TRACE, - CheckRequest.JSON_PROPERTY_CONTEXT + CheckRequest.JSON_PROPERTY_CONTEXT, + CheckRequest.JSON_PROPERTY_CONSISTENCY }) public class CheckRequest { public static final String JSON_PROPERTY_TUPLE_KEY = "tuple_key"; @@ -47,6 +48,9 @@ public class CheckRequest { public static final String JSON_PROPERTY_CONTEXT = "context"; private Object context; + public static final String JSON_PROPERTY_CONSISTENCY = "consistency"; + private ConsistencyPreference consistency = ConsistencyPreference.UNSPECIFIED; + public CheckRequest() {} @JsonCreator @@ -154,6 +158,28 @@ public void setContext(Object context) { this.context = context; } + public CheckRequest consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + /** + * Get consistency + * @return consistency + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public ConsistencyPreference getConsistency() { + return consistency; + } + + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setConsistency(ConsistencyPreference consistency) { + this.consistency = consistency; + } + /** * Return true if this Check_request object is equal to o. */ @@ -170,12 +196,13 @@ public boolean equals(Object o) { && Objects.equals(this.contextualTuples, checkRequest.contextualTuples) && Objects.equals(this.authorizationModelId, checkRequest.authorizationModelId) && Objects.equals(this.trace, checkRequest.trace) - && Objects.equals(this.context, checkRequest.context); + && Objects.equals(this.context, checkRequest.context) + && Objects.equals(this.consistency, checkRequest.consistency); } @Override public int hashCode() { - return Objects.hash(tupleKey, contextualTuples, authorizationModelId, trace, context); + return Objects.hash(tupleKey, contextualTuples, authorizationModelId, trace, context, consistency); } @Override @@ -191,6 +218,7 @@ public String toString() { .append("\n"); sb.append(" trace: ").append(toIndentedString(trace)).append("\n"); sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append(" consistency: ").append(toIndentedString(consistency)).append("\n"); sb.append("}"); return sb.toString(); } @@ -278,6 +306,16 @@ public String toUrlQueryString(String prefix) { .replaceAll("\\+", "%20"))); } + // add `consistency` to the URL query string + if (getConsistency() != null) { + joiner.add(String.format( + "%sconsistency%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getConsistency()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + return joiner.toString(); } } diff --git a/src/main/java/dev/openfga/sdk/api/model/ConsistencyPreference.java b/src/main/java/dev/openfga/sdk/api/model/ConsistencyPreference.java new file mode 100644 index 0000000..0f3fc51 --- /dev/null +++ b/src/main/java/dev/openfga/sdk/api/model/ConsistencyPreference.java @@ -0,0 +1,69 @@ +/* + * OpenFGA + * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. + * + * The version of the OpenAPI document: 1.x + * Contact: community@openfga.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package dev.openfga.sdk.api.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. + */ +public enum ConsistencyPreference { + UNSPECIFIED("UNSPECIFIED"), + + MINIMIZE_LATENCY("MINIMIZE_LATENCY"), + + HIGHER_CONSISTENCY("HIGHER_CONSISTENCY"), + + UNKNOWN_DEFAULT_OPEN_API("unknown_default_open_api"); + + private String value; + + ConsistencyPreference(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ConsistencyPreference fromValue(String value) { + for (ConsistencyPreference b : ConsistencyPreference.values()) { + if (b.value.equals(value)) { + return b; + } + } + return UNKNOWN_DEFAULT_OPEN_API; + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + if (prefix == null) { + prefix = ""; + } + + return String.format("%s=%s", prefix, this.toString()); + } +} diff --git a/src/main/java/dev/openfga/sdk/api/model/ExpandRequest.java b/src/main/java/dev/openfga/sdk/api/model/ExpandRequest.java index 98f7548..7772687 100644 --- a/src/main/java/dev/openfga/sdk/api/model/ExpandRequest.java +++ b/src/main/java/dev/openfga/sdk/api/model/ExpandRequest.java @@ -23,7 +23,11 @@ /** * ExpandRequest */ -@JsonPropertyOrder({ExpandRequest.JSON_PROPERTY_TUPLE_KEY, ExpandRequest.JSON_PROPERTY_AUTHORIZATION_MODEL_ID}) +@JsonPropertyOrder({ + ExpandRequest.JSON_PROPERTY_TUPLE_KEY, + ExpandRequest.JSON_PROPERTY_AUTHORIZATION_MODEL_ID, + ExpandRequest.JSON_PROPERTY_CONSISTENCY +}) public class ExpandRequest { public static final String JSON_PROPERTY_TUPLE_KEY = "tuple_key"; private ExpandRequestTupleKey tupleKey; @@ -31,6 +35,9 @@ public class ExpandRequest { public static final String JSON_PROPERTY_AUTHORIZATION_MODEL_ID = "authorization_model_id"; private String authorizationModelId; + public static final String JSON_PROPERTY_CONSISTENCY = "consistency"; + private ConsistencyPreference consistency = ConsistencyPreference.UNSPECIFIED; + public ExpandRequest() {} public ExpandRequest tupleKey(ExpandRequestTupleKey tupleKey) { @@ -77,6 +84,28 @@ public void setAuthorizationModelId(String authorizationModelId) { this.authorizationModelId = authorizationModelId; } + public ExpandRequest consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + /** + * Get consistency + * @return consistency + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public ConsistencyPreference getConsistency() { + return consistency; + } + + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setConsistency(ConsistencyPreference consistency) { + this.consistency = consistency; + } + /** * Return true if this Expand_request object is equal to o. */ @@ -90,12 +119,13 @@ public boolean equals(Object o) { } ExpandRequest expandRequest = (ExpandRequest) o; return Objects.equals(this.tupleKey, expandRequest.tupleKey) - && Objects.equals(this.authorizationModelId, expandRequest.authorizationModelId); + && Objects.equals(this.authorizationModelId, expandRequest.authorizationModelId) + && Objects.equals(this.consistency, expandRequest.consistency); } @Override public int hashCode() { - return Objects.hash(tupleKey, authorizationModelId); + return Objects.hash(tupleKey, authorizationModelId, consistency); } @Override @@ -106,6 +136,7 @@ public String toString() { sb.append(" authorizationModelId: ") .append(toIndentedString(authorizationModelId)) .append("\n"); + sb.append(" consistency: ").append(toIndentedString(consistency)).append("\n"); sb.append("}"); return sb.toString(); } @@ -168,6 +199,16 @@ public String toUrlQueryString(String prefix) { .replaceAll("\\+", "%20"))); } + // add `consistency` to the URL query string + if (getConsistency() != null) { + joiner.add(String.format( + "%sconsistency%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getConsistency()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + return joiner.toString(); } } diff --git a/src/main/java/dev/openfga/sdk/api/model/ListObjectsRequest.java b/src/main/java/dev/openfga/sdk/api/model/ListObjectsRequest.java index bccb089..1ca59a3 100644 --- a/src/main/java/dev/openfga/sdk/api/model/ListObjectsRequest.java +++ b/src/main/java/dev/openfga/sdk/api/model/ListObjectsRequest.java @@ -29,7 +29,8 @@ ListObjectsRequest.JSON_PROPERTY_RELATION, ListObjectsRequest.JSON_PROPERTY_USER, ListObjectsRequest.JSON_PROPERTY_CONTEXTUAL_TUPLES, - ListObjectsRequest.JSON_PROPERTY_CONTEXT + ListObjectsRequest.JSON_PROPERTY_CONTEXT, + ListObjectsRequest.JSON_PROPERTY_CONSISTENCY }) public class ListObjectsRequest { public static final String JSON_PROPERTY_AUTHORIZATION_MODEL_ID = "authorization_model_id"; @@ -50,6 +51,9 @@ public class ListObjectsRequest { public static final String JSON_PROPERTY_CONTEXT = "context"; private Object context; + public static final String JSON_PROPERTY_CONSISTENCY = "consistency"; + private ConsistencyPreference consistency = ConsistencyPreference.UNSPECIFIED; + public ListObjectsRequest() {} public ListObjectsRequest authorizationModelId(String authorizationModelId) { @@ -184,6 +188,28 @@ public void setContext(Object context) { this.context = context; } + public ListObjectsRequest consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + /** + * Get consistency + * @return consistency + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public ConsistencyPreference getConsistency() { + return consistency; + } + + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setConsistency(ConsistencyPreference consistency) { + this.consistency = consistency; + } + /** * Return true if this ListObjects_request object is equal to o. */ @@ -201,12 +227,13 @@ public boolean equals(Object o) { && Objects.equals(this.relation, listObjectsRequest.relation) && Objects.equals(this.user, listObjectsRequest.user) && Objects.equals(this.contextualTuples, listObjectsRequest.contextualTuples) - && Objects.equals(this.context, listObjectsRequest.context); + && Objects.equals(this.context, listObjectsRequest.context) + && Objects.equals(this.consistency, listObjectsRequest.consistency); } @Override public int hashCode() { - return Objects.hash(authorizationModelId, type, relation, user, contextualTuples, context); + return Objects.hash(authorizationModelId, type, relation, user, contextualTuples, context, consistency); } @Override @@ -223,6 +250,7 @@ public String toString() { .append(toIndentedString(contextualTuples)) .append("\n"); sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append(" consistency: ").append(toIndentedString(consistency)).append("\n"); sb.append("}"); return sb.toString(); } @@ -325,6 +353,16 @@ public String toUrlQueryString(String prefix) { .replaceAll("\\+", "%20"))); } + // add `consistency` to the URL query string + if (getConsistency() != null) { + joiner.add(String.format( + "%sconsistency%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getConsistency()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + return joiner.toString(); } } diff --git a/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java b/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java index ecca341..4efddd2 100644 --- a/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java +++ b/src/main/java/dev/openfga/sdk/api/model/ListUsersRequest.java @@ -31,7 +31,8 @@ ListUsersRequest.JSON_PROPERTY_RELATION, ListUsersRequest.JSON_PROPERTY_USER_FILTERS, ListUsersRequest.JSON_PROPERTY_CONTEXTUAL_TUPLES, - ListUsersRequest.JSON_PROPERTY_CONTEXT + ListUsersRequest.JSON_PROPERTY_CONTEXT, + ListUsersRequest.JSON_PROPERTY_CONSISTENCY }) public class ListUsersRequest { public static final String JSON_PROPERTY_AUTHORIZATION_MODEL_ID = "authorization_model_id"; @@ -52,6 +53,9 @@ public class ListUsersRequest { public static final String JSON_PROPERTY_CONTEXT = "context"; private Object context; + public static final String JSON_PROPERTY_CONSISTENCY = "consistency"; + private ConsistencyPreference consistency = ConsistencyPreference.UNSPECIFIED; + public ListUsersRequest() {} public ListUsersRequest authorizationModelId(String authorizationModelId) { @@ -202,6 +206,28 @@ public void setContext(Object context) { this.context = context; } + public ListUsersRequest consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + /** + * Get consistency + * @return consistency + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public ConsistencyPreference getConsistency() { + return consistency; + } + + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setConsistency(ConsistencyPreference consistency) { + this.consistency = consistency; + } + /** * Return true if this ListUsers_request object is equal to o. */ @@ -219,12 +245,14 @@ public boolean equals(Object o) { && Objects.equals(this.relation, listUsersRequest.relation) && Objects.equals(this.userFilters, listUsersRequest.userFilters) && Objects.equals(this.contextualTuples, listUsersRequest.contextualTuples) - && Objects.equals(this.context, listUsersRequest.context); + && Objects.equals(this.context, listUsersRequest.context) + && Objects.equals(this.consistency, listUsersRequest.consistency); } @Override public int hashCode() { - return Objects.hash(authorizationModelId, _object, relation, userFilters, contextualTuples, context); + return Objects.hash( + authorizationModelId, _object, relation, userFilters, contextualTuples, context, consistency); } @Override @@ -241,6 +269,7 @@ public String toString() { .append(toIndentedString(contextualTuples)) .append("\n"); sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append(" consistency: ").append(toIndentedString(consistency)).append("\n"); sb.append("}"); return sb.toString(); } @@ -357,6 +386,16 @@ public String toUrlQueryString(String prefix) { .replaceAll("\\+", "%20"))); } + // add `consistency` to the URL query string + if (getConsistency() != null) { + joiner.add(String.format( + "%sconsistency%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getConsistency()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + return joiner.toString(); } } diff --git a/src/main/java/dev/openfga/sdk/api/model/ReadRequest.java b/src/main/java/dev/openfga/sdk/api/model/ReadRequest.java index 85c2287..6d89ca0 100644 --- a/src/main/java/dev/openfga/sdk/api/model/ReadRequest.java +++ b/src/main/java/dev/openfga/sdk/api/model/ReadRequest.java @@ -26,7 +26,8 @@ @JsonPropertyOrder({ ReadRequest.JSON_PROPERTY_TUPLE_KEY, ReadRequest.JSON_PROPERTY_PAGE_SIZE, - ReadRequest.JSON_PROPERTY_CONTINUATION_TOKEN + ReadRequest.JSON_PROPERTY_CONTINUATION_TOKEN, + ReadRequest.JSON_PROPERTY_CONSISTENCY }) public class ReadRequest { public static final String JSON_PROPERTY_TUPLE_KEY = "tuple_key"; @@ -38,6 +39,9 @@ public class ReadRequest { public static final String JSON_PROPERTY_CONTINUATION_TOKEN = "continuation_token"; private String continuationToken; + public static final String JSON_PROPERTY_CONSISTENCY = "consistency"; + private ConsistencyPreference consistency = ConsistencyPreference.UNSPECIFIED; + public ReadRequest() {} public ReadRequest tupleKey(ReadRequestTupleKey tupleKey) { @@ -106,6 +110,28 @@ public void setContinuationToken(String continuationToken) { this.continuationToken = continuationToken; } + public ReadRequest consistency(ConsistencyPreference consistency) { + this.consistency = consistency; + return this; + } + + /** + * Get consistency + * @return consistency + **/ + @javax.annotation.Nullable + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public ConsistencyPreference getConsistency() { + return consistency; + } + + @JsonProperty(JSON_PROPERTY_CONSISTENCY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setConsistency(ConsistencyPreference consistency) { + this.consistency = consistency; + } + /** * Return true if this Read_request object is equal to o. */ @@ -120,12 +146,13 @@ public boolean equals(Object o) { ReadRequest readRequest = (ReadRequest) o; return Objects.equals(this.tupleKey, readRequest.tupleKey) && Objects.equals(this.pageSize, readRequest.pageSize) - && Objects.equals(this.continuationToken, readRequest.continuationToken); + && Objects.equals(this.continuationToken, readRequest.continuationToken) + && Objects.equals(this.consistency, readRequest.consistency); } @Override public int hashCode() { - return Objects.hash(tupleKey, pageSize, continuationToken); + return Objects.hash(tupleKey, pageSize, continuationToken, consistency); } @Override @@ -137,6 +164,7 @@ public String toString() { sb.append(" continuationToken: ") .append(toIndentedString(continuationToken)) .append("\n"); + sb.append(" consistency: ").append(toIndentedString(consistency)).append("\n"); sb.append("}"); return sb.toString(); } @@ -209,6 +237,16 @@ public String toUrlQueryString(String prefix) { .replaceAll("\\+", "%20"))); } + // add `consistency` to the URL query string + if (getConsistency() != null) { + joiner.add(String.format( + "%sconsistency%s=%s", + prefix, + suffix, + URLEncoder.encode(String.valueOf(getConsistency()), StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"))); + } + return joiner.toString(); } } diff --git a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java index bceac23..1250b36 100644 --- a/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java +++ b/src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java @@ -912,8 +912,8 @@ public void readTest() throws Exception { // Given String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.HIGHER_CONSISTENCY); String responseBody = String.format( "{\"tuples\":[{\"key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}}]}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -922,7 +922,8 @@ public void readTest() throws Exception { .tupleKey(new ReadRequestTupleKey() ._object(DEFAULT_OBJECT) .relation(DEFAULT_RELATION) - .user(DEFAULT_USER)); + .user(DEFAULT_USER)) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When var response = fga.read(DEFAULT_STORE_ID, request).get(); @@ -944,8 +945,8 @@ public void read_complexContext() throws Exception { // Given String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.HIGHER_CONSISTENCY); String responseBody = String.format( "{\"tuples\":[{\"key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"," + "\"condition\":{\"context\":{" @@ -965,7 +966,8 @@ public void read_complexContext() throws Exception { .tupleKey(new ReadRequestTupleKey() ._object(DEFAULT_OBJECT) .relation(DEFAULT_RELATION) - .user(DEFAULT_USER)); + .user(DEFAULT_USER)) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When var response = fga.read(DEFAULT_STORE_ID, request).get(); @@ -1313,8 +1315,8 @@ public void check() throws Exception { // Given String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[]},\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[]},\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.MINIMIZE_LATENCY); mockHttpClient.onPost(postPath).withBody(is(expectedBody)).doReturn(200, "{\"allowed\":true}"); CheckRequest request = new CheckRequest() .tupleKey(new CheckRequestTupleKey() @@ -1322,7 +1324,8 @@ public void check() throws Exception { .relation(DEFAULT_RELATION) .user(DEFAULT_USER)) .contextualTuples(new ContextualTupleKeys()) - .authorizationModelId(DEFAULT_AUTH_MODEL_ID); + .authorizationModelId(DEFAULT_AUTH_MODEL_ID) + .consistency(ConsistencyPreference.MINIMIZE_LATENCY); // When var response = fga.check(DEFAULT_STORE_ID, request).get(); @@ -1426,15 +1429,16 @@ public void expandTest() throws Exception { // Given String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; String expectedBody = String.format( - "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\"}", - DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); + "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\",\"consistency\":\"%s\"}", + DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID, ConsistencyPreference.HIGHER_CONSISTENCY); String responseBody = String.format( "{\"tree\":{\"root\":{\"union\":{\"nodes\":[{\"leaf\":{\"users\":{\"users\":[\"%s\"]}}}]}}}}", DEFAULT_USER); mockHttpClient.onPost(postPath).withBody(is(expectedBody)).doReturn(200, responseBody); ExpandRequest request = new ExpandRequest() .authorizationModelId(DEFAULT_AUTH_MODEL_ID) - .tupleKey(new ExpandRequestTupleKey()._object(DEFAULT_OBJECT).relation(DEFAULT_RELATION)); + .tupleKey(new ExpandRequestTupleKey()._object(DEFAULT_OBJECT).relation(DEFAULT_RELATION)) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When var response = fga.expand(DEFAULT_STORE_ID, request).get(); @@ -1551,8 +1555,8 @@ public void listObjectsTest() throws Exception { // Given String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; String expectedBody = String.format( - "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null}", - DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); + "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER, ConsistencyPreference.HIGHER_CONSISTENCY); mockHttpClient .onPost(postPath) .withBody(is(expectedBody)) @@ -1560,7 +1564,8 @@ public void listObjectsTest() throws Exception { ListObjectsRequest request = new ListObjectsRequest() .authorizationModelId(DEFAULT_AUTH_MODEL_ID) .relation(DEFAULT_RELATION) - .user(DEFAULT_USER); + .user(DEFAULT_USER) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When var response = fga.listObjects(DEFAULT_STORE_ID, request).get(); 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 7425cf6..189df4e 100644 --- a/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java +++ b/src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java @@ -55,6 +55,7 @@ public class OpenFgaClientTest { private static final String DEFAULT_ID = "budget"; private static final String DEFAULT_OBJECT = DEFAULT_TYPE + ":" + DEFAULT_ID; private static final String DEFAULT_SCHEMA_VERSION = "1.1"; + private static final ConsistencyPreference DEFAULT_CONSISTENCY = ConsistencyPreference.UNSPECIFIED; private static final String EMPTY_RESPONSE_BODY = "{}"; private static final ClientRelationshipCondition DEFAULT_CONDITION = new ClientRelationshipCondition().name("condition").context(Map.of("some", "context")); @@ -999,8 +1000,8 @@ public void readTest() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.MINIMIZE_LATENCY); String responseBody = String.format( "{\"tuples\":[{\"key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}}]}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1009,9 +1010,10 @@ public void readTest() throws Exception { .user(DEFAULT_USER) .relation(DEFAULT_RELATION) ._object(DEFAULT_OBJECT); + ClientReadOptions options = new ClientReadOptions().consistency(ConsistencyPreference.MINIMIZE_LATENCY); // When - ClientReadResponse response = fga.read(request).get(); + ClientReadResponse response = fga.read(request, options).get(); // Then mockHttpClient.verify().post(postUrl).withBody(is(expectedBody)).called(1); @@ -1028,7 +1030,8 @@ public void readTest() throws Exception { public void read_emptyRequestSendsNoTupleKey() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); - String expectedBody = "{\"tuple_key\":null,\"page_size\":null,\"continuation_token\":null}"; + String expectedBody = + "{\"tuple_key\":null,\"page_size\":null,\"continuation_token\":null,\"consistency\":\"UNSPECIFIED\"}"; mockHttpClient.onPost(postUrl).withBody(is(expectedBody)).doReturn(200, EMPTY_RESPONSE_BODY); ClientReadRequest request = new ClientReadRequest(); @@ -1554,8 +1557,13 @@ public void check() throws Exception { String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}," + "\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"owner\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}]}," - + "\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_USER, DEFAULT_OBJECT); + + "\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, + DEFAULT_RELATION, + DEFAULT_OBJECT, + DEFAULT_USER, + DEFAULT_OBJECT, + ConsistencyPreference.HIGHER_CONSISTENCY); mockHttpClient.onPost(postUrl).withBody(is(expectedBody)).doReturn(200, "{\"allowed\":true}"); ClientCheckRequest request = new ClientCheckRequest() ._object(DEFAULT_OBJECT) @@ -1566,7 +1574,9 @@ public void check() throws Exception { .relation("owner") .user(DEFAULT_USER) .condition(DEFAULT_CONDITION))); - ClientCheckOptions options = new ClientCheckOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID); + ClientCheckOptions options = new ClientCheckOptions() + .authorizationModelId(DEFAULT_AUTH_MODEL_ID) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When ClientCheckResponse response = fga.check(request, options).get(); @@ -1662,8 +1672,8 @@ public void batchCheck() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.MINIMIZE_LATENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -1674,7 +1684,9 @@ public void batchCheck() throws Exception { ._object(DEFAULT_OBJECT) .relation(DEFAULT_RELATION) .user(DEFAULT_USER); - ClientBatchCheckOptions options = new ClientBatchCheckOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID); + ClientBatchCheckOptions options = new ClientBatchCheckOptions() + .authorizationModelId(DEFAULT_AUTH_MODEL_ID) + .consistency(ConsistencyPreference.MINIMIZE_LATENCY); // When List response = @@ -1696,8 +1708,8 @@ public void batchCheck_twentyTimes() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -1825,15 +1837,17 @@ public void expandTest() throws Exception { // Given String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; String expectedBody = String.format( - "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\"}", - DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); + "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\",\"consistency\":\"%s\"}", + DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID, ConsistencyPreference.HIGHER_CONSISTENCY); String responseBody = String.format( "{\"tree\":{\"root\":{\"union\":{\"nodes\":[{\"leaf\":{\"users\":{\"users\":[\"%s\"]}}}]}}}}", DEFAULT_USER); mockHttpClient.onPost(postPath).withBody(is(expectedBody)).doReturn(200, responseBody); ClientExpandRequest request = new ClientExpandRequest().relation(DEFAULT_RELATION)._object(DEFAULT_OBJECT); - ClientExpandOptions options = new ClientExpandOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID); + ClientExpandOptions options = new ClientExpandOptions() + .authorizationModelId(DEFAULT_AUTH_MODEL_ID) + .consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When ClientExpandResponse response = fga.expand(request, options).get(); @@ -1940,17 +1954,19 @@ public void listObjectsTest() throws Exception { // Given String postPath = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null}", - DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); + "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER, ConsistencyPreference.HIGHER_CONSISTENCY); mockHttpClient .onPost(postPath) .withBody(is(expectedBody)) .doReturn(200, String.format("{\"objects\":[\"%s\"]}", DEFAULT_OBJECT)); ClientListObjectsRequest request = new ClientListObjectsRequest().relation(DEFAULT_RELATION).user(DEFAULT_USER); + ClientListObjectsOptions options = + new ClientListObjectsOptions().consistency(ConsistencyPreference.HIGHER_CONSISTENCY); // When - ClientListObjectsResponse response = fga.listObjects(request).get(); + ClientListObjectsResponse response = fga.listObjects(request, options).get(); // Then mockHttpClient.verify().post(postPath).withBody(is(expectedBody)).called(1); @@ -2041,8 +2057,8 @@ public void listObjectsWithContextTest() throws Exception { // Given String postPath = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":{\"some\":\"context\"}}", - DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); + "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":{\"some\":\"context\"},\"consistency\":\"%s\"}", + DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postPath) .withBody(is(expectedBody)) @@ -2068,8 +2084,8 @@ public void listRelations() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, ConsistencyPreference.MINIMIZE_LATENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2080,8 +2096,9 @@ public void listRelations() throws Exception { .relations(List.of(DEFAULT_RELATION)) .user(DEFAULT_USER) ._object(DEFAULT_OBJECT); - ClientListRelationsOptions options = - new ClientListRelationsOptions().authorizationModelId(DEFAULT_AUTH_MODEL_ID); + ClientListRelationsOptions options = new ClientListRelationsOptions() + .authorizationModelId(DEFAULT_AUTH_MODEL_ID) + .consistency(ConsistencyPreference.MINIMIZE_LATENCY); // When ClientListRelationsResponse response = @@ -2106,8 +2123,8 @@ public void listRelations_deny() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":null}", - DEFAULT_USER, "owner", DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, "owner", DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2198,8 +2215,8 @@ public void listRelations_400() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2228,8 +2245,8 @@ public void listRelations_404() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2257,8 +2274,8 @@ public void listRelations_500() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", - DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2286,14 +2303,15 @@ public void listRelations_contextAndContextualTuples() throws Exception { // Given String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":{\"some\":\"context\"}}", + "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":{\"some\":\"context\"},\"consistency\":\"%s\"}", DEFAULT_USER, "owner", DEFAULT_OBJECT, DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, - DEFAULT_AUTH_MODEL_ID); + DEFAULT_AUTH_MODEL_ID, + DEFAULT_CONSISTENCY); mockHttpClient .onPost(postUrl) .withBody(is(expectedBody)) @@ -2337,8 +2355,12 @@ public void listUsersTest() throws Exception { // Given String postPath = String.format("https://api.fga.example/stores/%s/list-users", DEFAULT_STORE_ID); String expectedBody = String.format( - "{\"authorization_model_id\":\"%s\",\"object\":{\"type\":\"%s\",\"id\":\"%s\"},\"relation\":\"%s\",\"user_filters\":[{\"type\":\"user\",\"relation\":null},{\"type\":\"team\",\"relation\":\"member\"}],\"contextual_tuples\":[],\"context\":null}", - DEFAULT_AUTH_MODEL_ID, DEFAULT_TYPE, DEFAULT_ID, DEFAULT_RELATION); + "{\"authorization_model_id\":\"%s\",\"object\":{\"type\":\"%s\",\"id\":\"%s\"},\"relation\":\"%s\",\"user_filters\":[{\"type\":\"user\",\"relation\":null},{\"type\":\"team\",\"relation\":\"member\"}],\"contextual_tuples\":[],\"context\":null,\"consistency\":\"%s\"}", + DEFAULT_AUTH_MODEL_ID, + DEFAULT_TYPE, + DEFAULT_ID, + DEFAULT_RELATION, + ConsistencyPreference.MINIMIZE_LATENCY); mockHttpClient .onPost(postPath) .withBody(is(expectedBody)) @@ -2355,9 +2377,11 @@ public void listUsersTest() throws Exception { add(new UserTypeFilter().type("team").relation("member")); } }); + ClientListUsersOptions options = + new ClientListUsersOptions().consistency(ConsistencyPreference.MINIMIZE_LATENCY); // When - ClientListUsersResponse response = fga.listUsers(request).get(); + ClientListUsersResponse response = fga.listUsers(request, options).get(); // Then mockHttpClient.verify().post(postPath).withBody(is(expectedBody)).called(1);