66[ ![ Discord Server] ( https://img.shields.io/discord/844600078504951838?color=7289da&logo=discord " Discord Server ")] ( https://discord.gg/jTysUaxXzM )
77[ ![ Twitter] ( https://img.shields.io/twitter/follow/authzed?color=%23179CF0&logo=twitter&style=flat-square )] ( https://twitter.com/authzed )
88
9- This repository houses the Java client library for [ SpiceDB] .
10-
11- [ SpiceDB] is a database and service that stores, computes, and validates your application's permissions.
9+ This repository houses the Java client library for [ SpiceDB] , a database and service that can store your application's permissions.
1210
1311Developers create a schema that models their permissions requirements and use a client library, such as this one, to apply the schema to the database, insert data into the database, and query the data to efficiently check permissions in their applications.
1412
15- Supported client API versions:
16- - [ v1] ( https://authzed.com/docs/reference/api#authzedapiv1 )
17-
1813You can find more info on each API on the [ SpiceDB API reference documentation] .
1914Additionally, Protobuf API documentation can be found on the [ Buf Registry SpiceDB API repository] .
2015Documentation for the latest Java client release is available as [ Javadoc] .
@@ -23,22 +18,20 @@ See [CONTRIBUTING.md] for instructions on contributing and performing common tas
2318
2419[ Authzed ] : https://authzed.com
2520[ SpiceDB ] : https://github.com/authzed/spicedb
26- [ SpiceDB API Reference documentation ] : https://authzed.com/docs/reference/ api
21+ [ SpiceDB API Reference documentation ] : https://authzed.com/docs/spicedb/api/http- api
2722[ Buf Registry SpiceDB API repository ] : https://buf.build/authzed/api/docs/main
2823[ CONTRIBUTING.md ] : CONTRIBUTING.md
2924[ Javadoc ] : https://authzed.github.io/authzed-java/index.html
3025
3126## Getting Started
3227
33- We highly recommend following the ** [ Protecting Your First App] ** guide to learn the latest best practice to integrate an application with SpiceDB.
28+ We highly recommend following the ** [ Protecting Your First App] ** guide to learn the latest best practices to integrate an application with SpiceDB.
3429
3530If you're interested in examples for a specific API version, they can be found in their respective folders in the [ examples directory] .
3631
3732[ Protecting Your First App ] : https://authzed.com/docs/guides/first-app
3833[ examples directory ] : /examples
3934
40- ## Basic Usage
41-
4235### Installation
4336
4437This project is packaged as the artifact ` authzed ` under the ` com.authzed.api ` group on [ Maven Central] .
@@ -70,7 +63,7 @@ If you are using [Gradle] then add the following to your `build.gradle` file:
7063
7164``` groovy
7265dependencies {
73- implementation "com.authzed.api:authzed:v1.0 .0"
66+ implementation "com.authzed.api:authzed:v1.3 .0"
7467 implementation 'io.grpc:grpc-api:1.72.0'
7568 implementation 'io.grpc:grpc-stub:1.72.0'
7669}
@@ -83,11 +76,6 @@ dependencies {
8376
8477### Initializing a client
8578
86- Because of how [ grpc-java] is designed, there is little in terms of abstraction over the gRPC APIs underpinning Authzed.
87- A ` ManagedChannel ` will establish a connection to Authzed that can be shared with _ stubs_ for each gRPC service.
88- To successfully authenticate with the API, you will have to provide a [ Bearer Token] with your own API Token
89- from the [ Authzed dashboard] or your local SpiceDB instance in place of ` t_your_token_here_1234567deadbeef ` as
90- ` CallCredentials ` for each stub:
9179
9280``` java
9381package org.example ;
@@ -99,12 +87,16 @@ import io.grpc.ManagedChannelBuilder;
9987
10088public class PermissionServiceExample {
10189 public static void main (String [] args ) {
90+ // establish a connection to Authzed
10291 ManagedChannel channel = ManagedChannelBuilder
10392 .forTarget(" grpc.authzed.com:443" )
10493 .useTransportSecurity()
10594 .build();
10695
96+ // get the bearer token from your Authzed dashboard (or from https://app.authzed.cloud)
10797 BearerToken bearerToken = new BearerToken (" t_your_token_here_1234567deadbeef" );
98+
99+ // create the client
108100 PermissionsServiceGrpc . PermissionsServiceBlockingStub permissionsService = PermissionsServiceGrpc
109101 .newBlockingStub(channel)
110102 .withCallCredentials(bearerToken);
@@ -123,9 +115,9 @@ ManagedChannel channel = ManagedChannelBuilder
123115
124116[ grpc-java ] : https://github.com/grpc/grpc-java
125117[ Bearer Token ] : https://authzed.com/docs/reference/api#authentication
126- [ Authzed dashboard ] : https://app.authzed.com /
118+ [ Authzed dashboard ] : https://app.authzed.cloud /
127119
128- ### Performing an API call
120+ ### Calling ` CheckPermission `
129121
130122Request and Response types are located in their respective gRPC Service packages and common types can be found in the Core package.
131123Referring to the [ Authzed ProtoBuf Documentation] is useful for discovering these APIs.
@@ -144,6 +136,7 @@ import com.authzed.grpcutil.BearerToken;
144136import io.grpc.ManagedChannel ;
145137import io.grpc.ManagedChannelBuilder ;
146138
139+
147140public class ClientExample {
148141 public static void main (String [] args ) {
149142 ManagedChannel channel = ManagedChannelBuilder
@@ -188,3 +181,66 @@ public class ClientExample {
188181 }
189182}
190183```
184+
185+ ### Calling ` Watch `
186+
187+ The ` Watch ` API, like other streaming APIs, can disconnect at any time, so it is important to handle retries and resume from the last response received.
188+
189+ ``` java
190+ package org.example ;
191+
192+ import com.authzed.api.v1.* ;
193+ import com.authzed.grpcutil.BearerToken ;
194+ import io.grpc.ManagedChannel ;
195+ import io.grpc.ManagedChannelBuilder ;
196+ import io.grpc.Status ;
197+ import io.grpc.StatusRuntimeException ;
198+ import java.util.Iterator ;
199+
200+ public class ClientExample {
201+ public static void main (String [] args ) {
202+ ManagedChannel channel = ManagedChannelBuilder
203+ .forTarget(" localhost:50051" )
204+ .usePlaintext()
205+ .build();
206+
207+ BearerToken bearerToken = new BearerToken (" t_your_token_here_1234567deadbeef" );
208+ WatchServiceGrpc . WatchServiceBlockingStub watchClient = WatchServiceGrpc
209+ .newBlockingStub(channel)
210+ .withCallCredentials(bearerToken);
211+
212+ ZedToken lastZedToken = ZedToken . newBuilder(). setToken(" " ). build();
213+
214+ while (true ) {
215+ try {
216+ WatchRequest . Builder builder = WatchRequest . newBuilder();
217+
218+ if (! lastZedToken. getToken(). isEmpty()) {
219+ builder. setOptionalStartCursor(lastZedToken);
220+ }
221+
222+ WatchRequest request = builder. build();
223+
224+ Iterator<WatchResponse > watchStream = watchClient. watch(request);
225+
226+ while (watchStream. hasNext()) {
227+ WatchResponse msg = watchStream. next();
228+ System . out. println(" Received watch response: " + msg);
229+
230+ if (! msg. getChangesThrough(). getToken(). isEmpty()) {
231+ lastZedToken = msg. getChangesThrough();
232+ }
233+ }
234+
235+ } catch (Exception e) {
236+ if (e instanceof StatusRuntimeException sre && sre. getStatus(). getCode(). equals(Status . UNAVAILABLE. getCode()) && sre. getMessage(). contains(" stream timeout" )) {
237+ // Stream got disconnected after inactivity. Retry
238+ } else {
239+ System . out. println(" Error calling watch: " + e. getMessage());
240+ return ;
241+ }
242+ }
243+ }
244+ }
245+ }
246+ ```
0 commit comments