Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion config/clients/java/config.overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"gitRepoId": "java-sdk",
"artifactId": "openfga-sdk",
"groupId": "dev.openfga",
"packageVersion": "0.9.3",
"packageVersion": "0.9.9",
Comment thread
SoulPancake marked this conversation as resolved.
"basePackage": "dev.openfga.sdk",
"apiPackage": "dev.openfga.sdk.api",
"authPackage": "dev.openfga.sdk.api.auth",
Expand Down Expand Up @@ -32,6 +32,8 @@
"enumUnknownDefaultCase": true,
"allowUnicodeIdentifiers": true,
"caseInsensitiveResponseHeaders": true,
"supportsCallingOtherEndpoints": true,
"hideClientBatchCheckToc": true,
"openTelemetryDocumentation": "docs/OpenTelemetry.md",
"files": {
"src/main/constants/FgaConstants.mustache": {
Expand Down
4 changes: 2 additions & 2 deletions config/clients/java/template/README_calling_api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ Similar to [check](#check), but instead of checking a single user-object relatio
> Passing `ClientBatchCheckOptions` is optional. All fields of `ClientBatchCheckOptions` are optional.

```java
var reequst = new ClientBatchCheckRequest().checks(
var request = new ClientBatchCheckRequest().checks(
List.of(
new ClientBatchCheckItem()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
Expand Down Expand Up @@ -463,7 +463,7 @@ var reequst = new ClientBatchCheckRequest().checks(
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("creator")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.correlationId("cor-3), // optional, one will be generated for you if not provided
.correlationId("cor-3"), // optional, one will be generated for you if not provided
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("deleter")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Maven Central](https://img.shields.io/maven-central/v/dev.openfga/openfga-sdk.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/dev.openfga/openfga-sdk)
[![Javadoc](https://javadoc.io/badge2/dev.openfga/openfga-sdk/javadoc.svg)](https://javadoc.io/doc/dev.openfga/openfga-sdk)
[![Socket Badge](https://badge.socket.dev/maven/package/dev.openfga:openfga-sdk)](https://socket.dev/maven/package/dev.openfga:openfga-sdk)
[![Socket Badge](https://badge.socket.dev/maven/package/dev.openfga:openfga-sdk/{{packageVersion}})](https://socket.dev/maven/package/dev.openfga:openfga-sdk) <!-- x-release-please-version -->
[![DeepWiki](https://img.shields.io/badge/DeepWiki-openfga%2Fjava--sdk-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/openfga/java-sdk)
10 changes: 6 additions & 4 deletions config/clients/java/template/README_initializing.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class Example {
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.credentials(new Credentials(
new ClientCredentials()
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER"))
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER")) // Full token endpoint URL, e.g. "https://issuer.fga.example/oauth/token"
.apiAudience(System.getenv("FGA_API_AUDIENCE"))
.clientId(System.getenv("FGA_CLIENT_ID"))
.clientSecret(System.getenv("FGA_CLIENT_SECRET"))
Expand All @@ -79,7 +79,9 @@ public class Example {
}
```

#### Oauth2 Credentials
#### OAuth2 Client Credentials

The SDK supports standard OAuth2 client credentials flow for any OAuth2-compliant provider (e.g. Keycloak, Okta). The `apiAudience` parameter is optional, and an optional `scopes` parameter can be provided as a space-separated string. The `apiTokenIssuer` can be set to either a hostname (e.g. `issuer.example.com`, which defaults to `https` and appends `/oauth/token`) or a full token endpoint URL (e.g. `https://mykeycloak.fga.example/realms/myrealm/protocol/openid-connect/token`).

```java
import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -97,8 +99,8 @@ public class Example {
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.credentials(new Credentials(
new ClientCredentials()
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER"))
.scopes(System.getenv("FGA_API_SCOPES")) // optional space separated scopes
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER")) // Full token endpoint URL, e.g. "https://mykeycloak.fga.example/realms/myrealm/protocol/openid-connect/token"
.scopes(System.getenv("FGA_API_SCOPES")) // Optional, space-separated scopes
.clientId(System.getenv("FGA_CLIENT_ID"))
.clientSecret(System.getenv("FGA_CLIENT_SECRET"))
));
Expand Down
14 changes: 13 additions & 1 deletion config/clients/java/template/README_installation.mustache
Original file line number Diff line number Diff line change
@@ -1,45 +1,57 @@
The {{appName}} Java SDK is available on [Maven Central](https://central.sonatype.com/).

The OpenFGA Java SDK currently supports **Java 11** as the minimum JDK version.
The OpenFGA Java SDK currently supports **Java 17** as the minimum JDK version.
Comment thread
SoulPancake marked this conversation as resolved.

It can be used with the following:

* Gradle (Groovy)

<!-- x-release-please-start-version -->
```groovy
implementation '{{groupId}}:{{artifactId}}:{{packageVersion}}'
```
<!-- x-release-please-end -->

* Gradle (Kotlin)

<!-- x-release-please-start-version -->
```kotlin
implementation("{{groupId}}:{{artifactId}}:{{packageVersion}}")
```
<!-- x-release-please-end -->

* Apache Maven

<!-- x-release-please-start-version -->
```xml
<dependency>
<groupId>{{groupId}}</groupId>
<artifactId>{{artifactId}}</artifactId>
<version>{{packageVersion}}</version>
</dependency>
```
<!-- x-release-please-end -->

* Ivy

<!-- x-release-please-start-version -->
```xml
<dependency org="{{groupId}}" name="{{artifactId}}" rev="{{packageVersion}}"/>
```
<!-- x-release-please-end -->

* SBT

<!-- x-release-please-start-version -->
```scala
libraryDependencies += "{{groupId}}" % "{{artifactId}}" % "{{packageVersion}}"
```
<!-- x-release-please-end -->

* Leiningen

<!-- x-release-please-start-version -->
```edn
[{{groupId}}/{{artifactId}} "{{packageVersion}}"]
```
<!-- x-release-please-end -->
107 changes: 106 additions & 1 deletion config/clients/java/template/README_retries.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,109 @@ try {
System.out.println("Error: " + error.getMessage());
}
}
```
```

### Calling Other Endpoints

The API Executor provides direct HTTP access to OpenFGA endpoints not yet wrapped by the SDK. It maintains the SDK's client configuration including authentication, telemetry, retries, and error handling.

Use cases:
- Calling endpoints not yet supported by the SDK
- Using an SDK version that lacks support for a particular endpoint
- Accessing custom endpoints that extend the OpenFGA API

Initialize the SDK normally and access the API Executor via the `fgaClient` instance:

```java
// Initialize the client, same as above
ClientConfiguration config = new ClientConfiguration()
.apiUrl("http://localhost:8080")
.storeId("01YCP46JKYM8FJCQ37NMBYHE5X");
OpenFgaClient fgaClient = new OpenFgaClient(config);

// Custom new endpoint that doesn't exist in the SDK yet
Map<String, Object> requestBody = Map.of(
"user", "user:bob",
"action", "custom_action",
"resource", "resource:123"
);

// Build the request
ApiExecutorRequestBuilder request = ApiExecutorRequestBuilder.builder("POST", "/stores/{store_id}/custom-endpoint")
.pathParam("store_id", storeId)
Comment thread
SoulPancake marked this conversation as resolved.
.queryParam("page_size", "20")
Comment thread
SoulPancake marked this conversation as resolved.
.queryParam("continuation_token", "eyJwayI6...")
.body(requestBody)
.header("X-Experimental-Feature", "enabled")
.build();
```

#### Example: Calling a new "Custom Endpoint" endpoint and handling raw response

```java
// Get raw response without automatic decoding
ApiResponse<String> rawResponse = fgaClient.apiExecutor().send(request).get();

String rawJson = rawResponse.getData();
System.out.println("Response: " + rawJson);

// You can access fields like headers, status code, etc. from rawResponse:
System.out.println("Status Code: " + rawResponse.getStatusCode());
System.out.println("Headers: " + rawResponse.getHeaders());
```

#### Example: Calling a new "Custom Endpoint" endpoint and decoding response into a struct

```java
// Define a class to hold the response
class CustomEndpointResponse {
private boolean allowed;
private String reason;

public boolean isAllowed() { return allowed; }
public void setAllowed(boolean allowed) { this.allowed = allowed; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
}

// Get response decoded into CustomEndpointResponse class
ApiResponse<CustomEndpointResponse> response = fgaClient.apiExecutor()
.send(request, CustomEndpointResponse.class)
.get();

CustomEndpointResponse customEndpointResponse = response.getData();
System.out.println("Allowed: " + customEndpointResponse.isAllowed());
System.out.println("Reason: " + customEndpointResponse.getReason());

// You can access fields like headers, status code, etc. from response:
System.out.println("Status Code: " + response.getStatusCode());
System.out.println("Headers: " + response.getHeaders());
```

#### Calling a streaming endpoint

For streaming endpoints, use `streamingApiExecutor` instead. Pass the response class directly — the SDK handles the rest. It delivers each response object to a consumer callback as it arrives, and returns a `CompletableFuture<Void>` that completes when the stream is exhausted.

```java
ApiExecutorRequestBuilder request = ApiExecutorRequestBuilder.builder(HttpMethod.POST, "/stores/{store_id}/streamed-list-objects")
.body(new ListObjectsRequest().user("user:anne").relation("viewer").type("document"))
.build();
Comment thread
SoulPancake marked this conversation as resolved.

fgaClient.streamingApiExecutor(StreamedListObjectsResponse.class)
.stream(
request,
response -> System.out.println("Object: " + response.getObject()), // called per object
error -> System.err.println("Stream error: " + error.getMessage()) // optional
)
.thenRun(() -> System.out.println("Streaming complete"))
.exceptionally(err -> {
System.err.println("Fatal error: " + err.getMessage());
return null;
});
```

For a complete working example, see [examples/api-executor](examples/api-executor).

#### Documentation

See [docs/ApiExecutor.md](docs/ApiExecutor.md) for complete API reference and examples for both `ApiExecutor` and `StreamingApiExecutor`.
Loading
Loading