Skip to content

Commit 2db7d04

Browse files
authored
docs(example): simplify streamed-list-objects (#171)
1 parent 355c6eb commit 2db7d04

File tree

11 files changed

+289
-339
lines changed

11 files changed

+289
-339
lines changed

.openapi-generator/FILES

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,9 @@ example/opentelemetry/main.py
116116
example/opentelemetry/requirements.txt
117117
example/opentelemetry/setup.cfg
118118
example/opentelemetry/setup.py
119-
example/streamed-list-objects/.env.example
120-
example/streamed-list-objects/.gitignore
121119
example/streamed-list-objects/README.md
122-
example/streamed-list-objects/asynchronous.py
123-
example/streamed-list-objects/requirements.txt
124-
example/streamed-list-objects/setup.cfg
125-
example/streamed-list-objects/setup.py
126-
example/streamed-list-objects/synchronous.py
120+
example/streamed-list-objects/example.py
121+
example/streamed-list-objects/model.json
127122
openfga_sdk/__init__.py
128123
openfga_sdk/api/__init__.py
129124
openfga_sdk/api/open_fga_api.py

example/streamed-list-objects/.env.example

Lines changed: 0 additions & 1 deletion
This file was deleted.

example/streamed-list-objects/.gitignore

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,22 @@
1-
# Streamed List Objects example for OpenFGA's Python SDK
1+
# Streamed List Objects Example
22

3-
This example demonstrates working with the `POST` `/stores/:id/streamed-list-objects` endpoint in OpenFGA using the Python SDK.
3+
This example demonstrates working with [OpenFGA's `/streamed-list-objects` endpoint](https://openfga.dev/api/service#/Relationship%20Queries/StreamedListObjects) using the Python SDK's `streamed_list_objects()` method.
44

55
## Prerequisites
66

7-
If you do not already have an OpenFGA instance running, you can start one using the following command:
7+
- Python 3.10+
8+
- OpenFGA running on `localhost:8080`
89

9-
```bash
10-
docker run -d -p 8080:8080 openfga/openfga
11-
```
12-
13-
## Configure the example
14-
15-
You may need to configure the example for your environment:
10+
You can start OpenFGA with Docker by running the following command:
1611

1712
```bash
18-
cp .env.example .env
13+
docker pull openfga/openfga && docker run -it --rm -p 8080:8080 openfga/openfga run
1914
```
2015

21-
Now edit the `.env` file and set the values as appropriate.
22-
2316
## Running the example
2417

25-
Begin by installing the required dependencies:
26-
27-
```bash
28-
pip install -r requirements.txt
29-
```
30-
31-
Next, run the example. You can use either the synchronous or asynchronous client:
32-
33-
```bash
34-
python asynchronous.py
35-
```
18+
No additional setup is required to run this example. Simply run the following command:
3619

3720
```bash
38-
python synchronous.py
21+
python example.py
3922
```

example/streamed-list-objects/asynchronous.py

Lines changed: 0 additions & 137 deletions
This file was deleted.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# ruff: noqa: E402
2+
3+
"""
4+
Python SDK for OpenFGA
5+
6+
API version: 1.x
7+
Website: https://openfga.dev
8+
Documentation: https://openfga.dev/docs
9+
Support: https://openfga.dev/community
10+
License: [Apache-2.0](https://github.com/openfga/python-sdk/blob/main/LICENSE)
11+
12+
NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
13+
"""
14+
15+
import asyncio
16+
import json
17+
import os
18+
import sys
19+
20+
21+
###
22+
# The following two lines are just a convenience for SDK development and testing,
23+
# and should not be used in your code. They allow you to run this example using the
24+
# local SDK code from the parent directory, rather than using the installed package.
25+
###
26+
sdk_path = os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "..", ".."))
27+
sys.path.insert(0, sdk_path)
28+
29+
from openfga_sdk.client import OpenFgaClient
30+
from openfga_sdk.client.configuration import ClientConfiguration
31+
from openfga_sdk.client.models.list_objects_request import ClientListObjectsRequest
32+
from openfga_sdk.client.models.tuple import ClientTuple
33+
from openfga_sdk.models.create_store_request import CreateStoreRequest
34+
35+
36+
async def create_store(openfga: OpenFgaClient) -> str:
37+
"""
38+
Create a temporary store. The store will be deleted at the end of the example.
39+
"""
40+
41+
response = await openfga.create_store(CreateStoreRequest(name="Demo Store"))
42+
return response.id
43+
44+
45+
async def write_model(openfga: OpenFgaClient) -> str:
46+
"""
47+
Load the authentication model from a file and write it to the server.
48+
"""
49+
50+
with open("model.json") as model:
51+
response = await openfga.write_authorization_model(json.loads(model.read()))
52+
return response.authorization_model_id
53+
54+
55+
async def write_tuples(openfga: OpenFgaClient, quantity: int) -> int:
56+
"""
57+
Write a variable number of tuples to the temporary store.
58+
"""
59+
60+
chunks = quantity // 100
61+
62+
for chunk in range(0, chunks):
63+
await openfga.write_tuples(
64+
[
65+
ClientTuple(
66+
user="user:anne",
67+
relation="owner",
68+
object=f"document:{chunk * 100 + t}",
69+
)
70+
for t in range(0, 100)
71+
],
72+
)
73+
74+
return quantity
75+
76+
77+
async def streamed_list_objects(
78+
openfga: OpenFgaClient, request: ClientListObjectsRequest
79+
):
80+
"""
81+
Send our request to the streaming endpoint, and iterate over the streamed responses.
82+
"""
83+
results = []
84+
85+
# Note that streamed_list_objects() is an asynchronous generator, so we could yield results as they come in.
86+
# For the sake of this example, we'll just collect all the results into a list and yield them all at once.
87+
88+
async for response in openfga.streamed_list_objects(request):
89+
results.append(response.object)
90+
91+
return results
92+
93+
94+
async def list_objects(openfga: OpenFgaClient, request: ClientListObjectsRequest):
95+
"""
96+
For comparison sake, here is the non-streamed version of the same call, using list_objects().
97+
Note that in the non-streamed version, the server will return a maximum of 1000 results.
98+
"""
99+
results = await openfga.list_objects(request)
100+
return results.objects
101+
102+
103+
async def main():
104+
configure = ClientConfiguration(
105+
api_url="http://localhost:8080",
106+
)
107+
108+
async with OpenFgaClient(configure) as openfga:
109+
# Create our temporary store
110+
store = await create_store(openfga)
111+
print(f"Created temporary store ({store})")
112+
113+
# Configure the SDK to use the temporary store for the rest of the example
114+
openfga.set_store_id(store)
115+
116+
# Load the authorization model from a file and write it to the server
117+
model = await write_model(openfga)
118+
print(f"Created temporary authorization model ({model})\n")
119+
120+
# Configure the SDK to use this authorization model for the rest of the example
121+
openfga.set_authorization_model_id(model)
122+
123+
# Write a bunch of example tuples to the temporary store
124+
wrote = await write_tuples(openfga, 2000)
125+
print(f"Wrote {wrote} tuples to the store.\n")
126+
127+
################################
128+
129+
# Craft a request to list all `documents` owned by `user:anne``
130+
request = ClientListObjectsRequest(
131+
type="document",
132+
relation="owner",
133+
user="user:anne",
134+
)
135+
136+
# Send a single request to the server using both the streamed and standard endpoints
137+
streamed_results = await streamed_list_objects(openfga, request)
138+
standard_results = await list_objects(openfga, request)
139+
140+
print(
141+
f"/streamed-list-objects returned {streamed_results.__len__()} objects in a single request.",
142+
)
143+
# print([r for r in streamed_results])
144+
145+
print(
146+
f"/list-objects returned {standard_results.__len__()} objects in a single request.",
147+
)
148+
# print([r for r in standard_results])
149+
150+
################################
151+
152+
# Finally, delete the temporary store.
153+
await openfga.delete_store()
154+
print(f"\nDeleted temporary store ({store})")
155+
156+
157+
if __name__ == "__main__":
158+
asyncio.run(main())

0 commit comments

Comments
 (0)