Skip to content

Commit 5a80169

Browse files
committed
add code snippet for Watch API
1 parent 7fb2043 commit 5a80169

1 file changed

Lines changed: 74 additions & 18 deletions

File tree

README.md

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@
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

1311
Developers 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-
1813
You can find more info on each API on the [SpiceDB API reference documentation].
1914
Additionally, Protobuf API documentation can be found on the [Buf Registry SpiceDB API repository].
2015
Documentation 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

3530
If 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

4437
This 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
7265
dependencies {
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
9381
package org.example;
@@ -99,12 +87,16 @@ import io.grpc.ManagedChannelBuilder;
9987

10088
public 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

130122
Request and Response types are located in their respective gRPC Service packages and common types can be found in the Core package.
131123
Referring to the [Authzed ProtoBuf Documentation] is useful for discovering these APIs.
@@ -144,6 +136,7 @@ import com.authzed.grpcutil.BearerToken;
144136
import io.grpc.ManagedChannel;
145137
import io.grpc.ManagedChannelBuilder;
146138

139+
147140
public 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

Comments
 (0)