Skip to content

Commit 198b0f5

Browse files
authored
feat: add example project (#63)
2 parents 3997f23 + 3eacf2a commit 198b0f5

File tree

5 files changed

+290
-0
lines changed

5 files changed

+290
-0
lines changed

.openapi-generator/FILES

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ credentials/credentials.ts
2626
credentials/index.ts
2727
credentials/types.ts
2828
errors.ts
29+
example/Makefile
30+
example/README.md
31+
example/example1/example1.mjs
32+
example/example1/package.json
2933
git_push.sh
3034
index.ts
3135
package-lock.json

example/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
all: run
2+
3+
project_name=example1
4+
openfga_version=latest
5+
6+
setup:
7+
npm --prefix "${project_name}" install
8+
9+
run:
10+
npm --prefix "${project_name}" run start
11+
12+
run-openfga:
13+
docker pull docker.io/openfga/openfga:${openfga_version} && \
14+
docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version} run

example/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Examples of using the OpenFGA JS SDK
2+
3+
A set of Examples on how to call the OpenFGA JS SDK
4+
5+
### Examples
6+
Example 1:
7+
A bare-bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access.
8+
9+
### Running the Examples
10+
11+
Prerequisites:
12+
- `docker`
13+
- `make`
14+
- `Node.js` 16.13.0+
15+
16+
#### Run using a published SDK
17+
18+
Steps
19+
1. Clone/Copy the example folder
20+
2. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
21+
3. Run `make setup` to install dependencies
22+
4. Run `make run` to run the example
23+
24+
#### Run using a local unpublished SDK build
25+
26+
Steps
27+
1. Build the SDK
28+
2. In the Example `package.json` change the `@openfga/sdk` dependency from a semver range like below
29+
```json
30+
"dependencies": {
31+
"@openfga/sdk": "^0.3.1"
32+
}
33+
```
34+
to a `file:` reference like below
35+
```json
36+
"dependencies": {
37+
"@openfga/sdk": "file:../../"
38+
}
39+
```
40+
3. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
41+
4. Run `make setup` to install dependencies
42+
5. Run `make run` to run the example

example/example1/example1.mjs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import { Credentials, CredentialsMethod, FgaApiValidationError, OpenFgaClient, TypeName } from "@openfga/sdk";
2+
3+
async function main () {
4+
let credentials;
5+
if (process.env.FGA_CLIENT_ID) {
6+
credentials = new Credentials({
7+
method: CredentialsMethod.ClientCredentials,
8+
config: {
9+
clientId: process.env.FGA_CLIENT_ID,
10+
clientSecret: process.env.FGA_CLIENT_SECRET,
11+
apiAudience: process.env.FGA_API_AUDIENCE,
12+
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER
13+
}
14+
});
15+
}
16+
17+
const fgaClient = new OpenFgaClient({
18+
apiUrl: process.env.FGA_API_URL || "http://localhost:8080",
19+
storeId: process.env.FGA_STORE_ID, // not needed when calling `createStore` or `listStores`
20+
authorizationModelId: process.env.FGA_AUTHORIZATION_MODEL_ID, // optional, recommended for production,
21+
credentials
22+
});
23+
24+
console.log("Listing stores");
25+
const initialStores = await fgaClient.listStores();
26+
console.log(`Stores count: ${initialStores.stores.length}`);
27+
28+
console.log("Creating Test Store");
29+
const createdStore = await fgaClient.createStore({name: "Test Store"});
30+
const store = createdStore;
31+
console.log(`Test Store ID: ${store.id}`);
32+
33+
// Set the store ID
34+
fgaClient.storeId = store.id;
35+
36+
console.log("Listing Stores");
37+
const { stores } = await fgaClient.listStores();
38+
console.log(`Stores count: ${stores.length}`);
39+
40+
console.log("Getting Current Store");
41+
const currentStore = await fgaClient.getStore();
42+
console.log(`Current Store Name ${currentStore.name}`);
43+
44+
console.log("Reading Authorization Models");
45+
const { authorization_models } = await fgaClient.readAuthorizationModels();
46+
console.log(`Models Count: ${authorization_models.length}`);
47+
48+
console.log("Reading Latest Authorization Model");
49+
const { authorization_model } = await fgaClient.readLatestAuthorizationModel();
50+
if (authorization_model) {
51+
console.log(`Latest Authorization Model ID: ${latestModel.authorization_model.id}`);
52+
} else {
53+
console.log("Latest Authorization Model not found");
54+
}
55+
56+
console.log("Writing an Authorization Model");
57+
const model = await fgaClient.writeAuthorizationModel({
58+
schema_version: "1.1",
59+
type_definitions: [
60+
{
61+
type: "user"
62+
},
63+
{
64+
type: "document",
65+
relations: {
66+
writer: { this: {} },
67+
viewer: {
68+
union: {
69+
child: [
70+
{ this: {} },
71+
{
72+
computedUserset: {
73+
relation: "writer"
74+
}
75+
}
76+
]
77+
}
78+
}
79+
},
80+
metadata: {
81+
relations: {
82+
writer: {
83+
directly_related_user_types: [
84+
{ type: "user" },
85+
{ type: "user", condition: "ViewCountLessThan200" }
86+
]
87+
},
88+
viewer: {
89+
directly_related_user_types: [
90+
{ type: "user" }
91+
]
92+
}
93+
}
94+
}
95+
},
96+
],
97+
conditions: {
98+
"ViewCountLessThan200": {
99+
name: "ViewCountLessThan200",
100+
expression: "ViewCount < 200",
101+
parameters: {
102+
ViewCount: {
103+
type_name: TypeName.Int
104+
},
105+
Type: {
106+
type_name: TypeName.String
107+
},
108+
Name: {
109+
type_name: TypeName.String
110+
}
111+
}
112+
}
113+
}
114+
});
115+
const authorizationModelId = model.authorization_model_id;
116+
console.log(`Authorization Model ID: ${authorizationModelId}`);
117+
118+
console.log("Reading Authorization Models");
119+
const models = await fgaClient.readAuthorizationModels();
120+
console.log(`Models Count: ${models.authorization_models.length}`);
121+
122+
console.log("Reading Latest Authorization Model");
123+
const latestModel = await fgaClient.readLatestAuthorizationModel();
124+
console.log(`Latest Authorization Model ID: ${latestModel.authorization_model.id}`);
125+
126+
console.log("Writing Tuples");
127+
await fgaClient.write({
128+
writes: [
129+
{
130+
user: "user:anne",
131+
relation: "writer",
132+
object: "document:roadmap",
133+
condition: {
134+
name: "ViewCountLessThan200",
135+
context: {
136+
Name: "Roadmap",
137+
Type: "document"
138+
}
139+
}
140+
}
141+
]
142+
}, { authorizationModelId });
143+
console.log("Done Writing Tuples");
144+
145+
// Set the model ID
146+
fgaClient.authorizationModelId = authorizationModelId;
147+
148+
console.log("Reading Tuples");
149+
const { tuples } = await fgaClient.read();
150+
console.log(`Read Tuples: ${JSON.stringify(tuples)}`);
151+
152+
console.log("Reading Tuple Changes");
153+
const { changes } = await fgaClient.readChanges();
154+
console.log(`Tuple Changes: ${JSON.stringify(changes)}`);
155+
156+
console.log("Checking for access");
157+
try {
158+
const { allowed } = await fgaClient.check({
159+
user: "user:anne",
160+
relation: "viewer",
161+
object: "document:roadmap"
162+
});
163+
console.log(`Allowed: ${allowed}`);
164+
} catch (error) {
165+
if (error instanceof FgaApiValidationError) {
166+
console.log(`Failed due to ${error.apiErrorMessage}`);
167+
} else {
168+
throw error;
169+
}
170+
}
171+
172+
console.log("Checking for access with context");
173+
const { allowed } = await fgaClient.check({
174+
user: "user:anne",
175+
relation: "viewer",
176+
object: "document:roadmap",
177+
context: {
178+
ViewCount: 100
179+
}
180+
});
181+
console.log(`Allowed: ${allowed}`);
182+
183+
console.log("Writing Assertions");
184+
await fgaClient.writeAssertions([
185+
{
186+
user: "user:carl",
187+
relation: "writer",
188+
object: "document:budget",
189+
expectation: true
190+
},
191+
{
192+
user: "user:carl",
193+
relation: "writer",
194+
object: "document:roadmap",
195+
expectation: false
196+
}
197+
]);
198+
console.log("Assertions Updated");
199+
200+
console.log("Reading Assertions");
201+
const { assertions} = await fgaClient.readAssertions();
202+
console.log(`Assertions: ${JSON.stringify(assertions)}`);
203+
204+
console.log("Deleting Current Store");
205+
await fgaClient.deleteStore();
206+
console.log(`Deleted Store Count: ${store.id}`);
207+
}
208+
209+
main()
210+
.catch(error => {
211+
console.error(`error: ${error}`);
212+
process.exitCode = 1;
213+
});

example/example1/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "example1",
3+
"private": "true",
4+
"version": "1.0.0",
5+
"description": "A bare bones example of using the OpenFGA SDK",
6+
"author": "OpenFGA",
7+
"license": "Apache-2.0",
8+
"scripts": {
9+
"start": "node example1.mjs"
10+
},
11+
"dependencies": {
12+
"@openfga/sdk": "^0.3.1"
13+
},
14+
"engines": {
15+
"node": ">=16.13.0"
16+
}
17+
}

0 commit comments

Comments
 (0)