Skip to content

Commit 023259f

Browse files
authored
Merge pull request #137 from authzed/add-watch-code-snippet
add code snippet for Watch API
2 parents fbe78e1 + 599bdf2 commit 023259f

File tree

3 files changed

+99
-22
lines changed

3 files changed

+99
-22
lines changed

README.md

Lines changed: 18 additions & 22 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,21 +18,16 @@ 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.
34-
35-
If you're interested in examples for a specific API version, they can be found in their respective folders in the [examples directory].
28+
We highly recommend following the **[Protecting Your First App]** guide to learn the latest best practices to integrate an application with SpiceDB.
3629

3730
[Protecting Your First App]: https://authzed.com/docs/guides/first-app
38-
[examples directory]: /examples
39-
40-
## Basic Usage
4131

4232
### Installation
4333

@@ -70,7 +60,7 @@ If you are using [Gradle] then add the following to your `build.gradle` file:
7060

7161
```groovy
7262
dependencies {
73-
implementation "com.authzed.api:authzed:v1.0.0"
63+
implementation "com.authzed.api:authzed:1.4.1"
7464
implementation 'io.grpc:grpc-api:1.72.0'
7565
implementation 'io.grpc:grpc-stub:1.72.0'
7666
}
@@ -83,11 +73,6 @@ dependencies {
8373

8474
### Initializing a client
8575

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:
9176

9277
```java
9378
package org.example;
@@ -99,12 +84,16 @@ import io.grpc.ManagedChannelBuilder;
9984

10085
public class PermissionServiceExample {
10186
public static void main(String[] args) {
87+
// establish a connection to Authzed
10288
ManagedChannel channel = ManagedChannelBuilder
10389
.forTarget("grpc.authzed.com:443")
10490
.useTransportSecurity()
10591
.build();
10692

93+
// get the bearer token from your Authzed dashboard (or from https://app.authzed.cloud)
10794
BearerToken bearerToken = new BearerToken("t_your_token_here_1234567deadbeef");
95+
96+
// create the client
10897
PermissionsServiceGrpc.PermissionsServiceBlockingStub permissionsService = PermissionsServiceGrpc
10998
.newBlockingStub(channel)
11099
.withCallCredentials(bearerToken);
@@ -123,16 +112,16 @@ ManagedChannel channel = ManagedChannelBuilder
123112

124113
[grpc-java]: https://github.com/grpc/grpc-java
125114
[Bearer Token]: https://authzed.com/docs/reference/api#authentication
126-
[Authzed dashboard]: https://app.authzed.com/
115+
[Authzed dashboard]: https://app.authzed.cloud/
127116

128-
### Performing an API call
117+
### Calling `CheckPermission`
129118

130119
Request and Response types are located in their respective gRPC Service packages and common types can be found in the Core package.
131120
Referring to the [Authzed ProtoBuf Documentation] is useful for discovering these APIs.
132121

133122
Because of the verbosity of these types, we recommend writing your own functions/methods to create these types from your existing application's models.
134123

135-
The following example initializes a permission client, performs a `CheckPermission` call and prints the result
124+
The following example initializes a permission client, performs a `CheckPermission` call and prints the result.
136125

137126
[Authzed Protobuf Documentation]: https://buf.build/authzed/api/docs/main
138127

@@ -188,3 +177,10 @@ public class ClientExample {
188177
}
189178
}
190179
```
180+
181+
182+
### More examples
183+
184+
See the [examples directory] for more code snippets.
185+
186+
[examples directory]: /examples

examples/v1/CallingWatch.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Authzed API examples
3+
*/
4+
package v1;
5+
6+
import com.authzed.api.v1.*;
7+
import com.authzed.grpcutil.BearerToken;
8+
import io.grpc.ManagedChannel;
9+
import io.grpc.ManagedChannelBuilder;
10+
import io.grpc.Status;
11+
import io.grpc.StatusRuntimeException;
12+
import java.util.Iterator;
13+
14+
// Installation
15+
// https://search.maven.org/artifact/com.authzed.api/authzed
16+
17+
public class App {
18+
private static final Logger logger = Logger.getLogger(App.class.getName());
19+
private static final String target = "grpc.authzed.com:443";
20+
private static final String token = "tc_test_def_token";
21+
22+
private final SchemaServiceGrpc.SchemaServiceBlockingStub schemaService;
23+
private final PermissionsServiceGrpc.PermissionsServiceBlockingStub permissionsService;
24+
25+
public App(Channel channel) {
26+
BearerToken bearerToken = new BearerToken(token);
27+
WatchServiceGrpc.WatchServiceBlockingStub watchClient = WatchServiceGrpc
28+
.newBlockingStub(channel)
29+
.withCallCredentials(bearerToken);
30+
}
31+
32+
public static void main(String[] args) {
33+
ManagedChannel channel = ManagedChannelBuilder
34+
.forTarget(target)
35+
.useTransportSecurity() // if not using TLS, replace with .usePlaintext()
36+
.build();
37+
38+
ZedToken lastZedToken = ZedToken.newBuilder().setToken("").build();
39+
40+
while(true) {
41+
try {
42+
WatchRequest.Builder builder = WatchRequest.newBuilder()
43+
.addOptionalUpdateKinds(com.authzed.api.v1.WatchKind.WATCH_KIND_INCLUDE_CHECKPOINTS);
44+
45+
if (!lastZedToken.getToken().isEmpty()) {
46+
System.out.println("Resuming watch from token: " + lastZedToken.getToken());
47+
builder.setOptionalStartCursor(lastZedToken);
48+
}
49+
50+
WatchRequest request = builder.build();
51+
52+
Iterator<WatchResponse> watchStream = watchClient.watch(request);
53+
54+
while (watchStream.hasNext()) {
55+
WatchResponse msg = watchStream.next();
56+
57+
if (msg.getUpdatesCount() > 0) {
58+
for (var update : msg.getUpdatesList()) {
59+
System.out.println("Received update: " + update);
60+
}
61+
} else {
62+
System.out.println("No changes made in SpiceDB");
63+
}
64+
65+
if (!msg.getChangesThrough().getToken().isEmpty()) {
66+
lastZedToken = msg.getChangesThrough();
67+
}
68+
}
69+
70+
} catch (Exception e) {
71+
if (e instanceof StatusRuntimeException sre && (sre.getStatus().getCode().equals(Status.UNAVAILABLE.getCode()) ||
72+
(sre.getStatus().getCode().equals(Status.INTERNAL.getCode())) && sre.getMessage().contains("stream timeout"))) {
73+
// Probably a server restart. Retry.
74+
} else {
75+
System.out.println("Error calling watch: " + e.getMessage());
76+
return;
77+
}
78+
}
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)