Skip to content

Commit 1ba7b3d

Browse files
committed
feat: example for existing endpoints
1 parent 1e71e79 commit 1ba7b3d

File tree

1 file changed

+271
-0
lines changed

1 file changed

+271
-0
lines changed
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# ruff: noqa: E402
2+
3+
"""
4+
execute_api_request example — calls real OpenFGA endpoints and compares
5+
the results with the regular SDK methods to verify correctness.
6+
7+
Requires a running OpenFGA server (default: http://localhost:8080).
8+
export FGA_API_URL=http://localhost:8080 # optional, this is the default
9+
python3 execute_api_request_example.py
10+
"""
11+
12+
import asyncio
13+
import os
14+
import sys
15+
16+
sdk_path = os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "..", ".."))
17+
sys.path.insert(0, sdk_path)
18+
19+
from openfga_sdk import (
20+
ClientConfiguration,
21+
CreateStoreRequest,
22+
Metadata,
23+
ObjectRelation,
24+
OpenFgaClient,
25+
RelationMetadata,
26+
RelationReference,
27+
TypeDefinition,
28+
Userset,
29+
Usersets,
30+
WriteAuthorizationModelRequest,
31+
)
32+
from openfga_sdk.client.models import (
33+
ClientCheckRequest,
34+
ClientTuple,
35+
ClientWriteRequest,
36+
)
37+
from openfga_sdk.credentials import Credentials
38+
39+
40+
async def main():
41+
api_url = os.getenv("FGA_API_URL", "http://localhost:8080")
42+
43+
configuration = ClientConfiguration(
44+
api_url=api_url,
45+
credentials=Credentials(),
46+
)
47+
48+
async with OpenFgaClient(configuration) as fga_client:
49+
50+
# ─── Setup: create a store, model, and tuple ─────────────
51+
print("=== Setup ===")
52+
53+
# Create a test store via the SDK
54+
store = await fga_client.create_store(
55+
CreateStoreRequest(name="execute_api_request_test")
56+
)
57+
fga_client.set_store_id(store.id)
58+
print(f"Created store: {store.id}")
59+
60+
# Write an authorization model
61+
model_resp = await fga_client.write_authorization_model(
62+
WriteAuthorizationModelRequest(
63+
schema_version="1.1",
64+
type_definitions=[
65+
TypeDefinition(type="user"),
66+
TypeDefinition(
67+
type="document",
68+
relations=dict(
69+
writer=Userset(this=dict()),
70+
viewer=Userset(
71+
union=Usersets(
72+
child=[
73+
Userset(this=dict()),
74+
Userset(
75+
computed_userset=ObjectRelation(
76+
object="", relation="writer"
77+
)
78+
),
79+
]
80+
)
81+
),
82+
),
83+
metadata=Metadata(
84+
relations=dict(
85+
writer=RelationMetadata(
86+
directly_related_user_types=[
87+
RelationReference(type="user"),
88+
]
89+
),
90+
viewer=RelationMetadata(
91+
directly_related_user_types=[
92+
RelationReference(type="user"),
93+
]
94+
),
95+
)
96+
),
97+
),
98+
],
99+
)
100+
)
101+
auth_model_id = model_resp.authorization_model_id
102+
fga_client.set_authorization_model_id(auth_model_id)
103+
print(f"Created model: {auth_model_id}")
104+
105+
# Write a tuple
106+
await fga_client.write(
107+
ClientWriteRequest(
108+
writes=[
109+
ClientTuple(
110+
user="user:anne",
111+
relation="writer",
112+
object="document:roadmap",
113+
),
114+
]
115+
)
116+
)
117+
print("Wrote tuple: user:anne → writer → document:roadmap")
118+
119+
# ─── Tests ────────────────────────────────────────────────
120+
print("\n=== execute_api_request tests ===\n")
121+
122+
# ── 1. GET /stores ────────────────────────────────────────
123+
print("1. ListStores (GET /stores)")
124+
raw = await fga_client.execute_api_request(
125+
operation_name="ListStores",
126+
method="GET",
127+
path="/stores",
128+
query_params={"page_size": 100},
129+
)
130+
sdk = await fga_client.list_stores()
131+
body = raw.json()
132+
assert raw.status == 200, f"Expected 200, got {raw.status}"
133+
assert "stores" in body
134+
assert len(body["stores"]) == len(sdk.stores), (
135+
f"Count mismatch: {len(body['stores'])} vs {len(sdk.stores)}"
136+
)
137+
print(f" ✅ {len(body['stores'])} stores (status {raw.status})")
138+
139+
# ── 2. GET /stores/{store_id} (auto-substitution) ────────
140+
print("2. GetStore (GET /stores/{store_id})")
141+
raw = await fga_client.execute_api_request(
142+
operation_name="GetStore",
143+
method="GET",
144+
path="/stores/{store_id}",
145+
)
146+
sdk = await fga_client.get_store()
147+
body = raw.json()
148+
assert raw.status == 200
149+
assert body["id"] == sdk.id
150+
assert body["name"] == sdk.name
151+
print(f" ✅ id={body['id']}, name={body['name']}")
152+
153+
# ── 3. GET /stores/{store_id}/authorization-models ────────
154+
print("3. ReadAuthorizationModels (GET /stores/{store_id}/authorization-models)")
155+
raw = await fga_client.execute_api_request(
156+
operation_name="ReadAuthorizationModels",
157+
method="GET",
158+
path="/stores/{store_id}/authorization-models",
159+
)
160+
sdk = await fga_client.read_authorization_models()
161+
body = raw.json()
162+
assert raw.status == 200
163+
assert len(body["authorization_models"]) == len(sdk.authorization_models)
164+
print(f" ✅ {len(body['authorization_models'])} models")
165+
166+
# ── 4. POST /stores/{store_id}/check ──────────────────────
167+
print("4. Check (POST /stores/{store_id}/check)")
168+
raw = await fga_client.execute_api_request(
169+
operation_name="Check",
170+
method="POST",
171+
path="/stores/{store_id}/check",
172+
body={
173+
"tuple_key": {
174+
"user": "user:anne",
175+
"relation": "viewer",
176+
"object": "document:roadmap",
177+
},
178+
"authorization_model_id": auth_model_id,
179+
},
180+
)
181+
sdk = await fga_client.check(
182+
ClientCheckRequest(
183+
user="user:anne",
184+
relation="viewer",
185+
object="document:roadmap",
186+
)
187+
)
188+
body = raw.json()
189+
assert raw.status == 200
190+
assert body["allowed"] == sdk.allowed
191+
print(f" ✅ allowed={body['allowed']}")
192+
193+
# ── 5. POST /stores/{store_id}/read ───────────────────────
194+
print("5. Read (POST /stores/{store_id}/read)")
195+
raw = await fga_client.execute_api_request(
196+
operation_name="Read",
197+
method="POST",
198+
path="/stores/{store_id}/read",
199+
body={
200+
"tuple_key": {
201+
"user": "user:anne",
202+
"object": "document:",
203+
},
204+
},
205+
)
206+
body = raw.json()
207+
assert raw.status == 200
208+
assert "tuples" in body
209+
assert len(body["tuples"]) >= 1
210+
print(f" ✅ {len(body['tuples'])} tuples returned")
211+
212+
# ── 6. POST /stores — create store via raw request ────────
213+
print("6. CreateStore (POST /stores)")
214+
raw = await fga_client.execute_api_request(
215+
operation_name="CreateStore",
216+
method="POST",
217+
path="/stores",
218+
body={"name": "raw_request_test_store"},
219+
)
220+
body = raw.json()
221+
assert raw.status == 201, f"Expected 201, got {raw.status}"
222+
assert "id" in body
223+
new_store_id = body["id"]
224+
print(f" ✅ created store: {new_store_id}")
225+
226+
# ── 7. DELETE /stores/{store_id} — clean up ───────────────
227+
print("7. DeleteStore (DELETE /stores/{store_id})")
228+
raw = await fga_client.execute_api_request(
229+
operation_name="DeleteStore",
230+
method="DELETE",
231+
path="/stores/{store_id}",
232+
path_params={"store_id": new_store_id},
233+
)
234+
assert raw.status == 204, f"Expected 204, got {raw.status}"
235+
print(f" ✅ deleted store: {new_store_id} (status 204 No Content)")
236+
237+
# ── 8. Custom headers ─────────────────────────────────────
238+
print("8. Custom headers (GET /stores/{store_id})")
239+
raw = await fga_client.execute_api_request(
240+
operation_name="GetStoreWithHeaders",
241+
method="GET",
242+
path="/stores/{store_id}",
243+
headers={"X-Custom-Header": "test-value"},
244+
)
245+
assert raw.status == 200
246+
print(f" ✅ custom headers accepted (status {raw.status})")
247+
248+
# ── 9. Explicit path_params override for store_id ─────────
249+
print("9. Explicit store_id in path_params")
250+
raw = await fga_client.execute_api_request(
251+
operation_name="GetStore",
252+
method="GET",
253+
path="/stores/{store_id}",
254+
path_params={"store_id": store.id},
255+
)
256+
body = raw.json()
257+
assert raw.status == 200
258+
assert body["id"] == store.id
259+
print(f" ✅ explicit store_id matched: {body['id']}")
260+
261+
# ─── Cleanup ─────────────────────────────────────────────
262+
print("\n=== Cleanup ===")
263+
await fga_client.delete_store()
264+
print(f"Deleted test store: {store.id}")
265+
266+
print("\n All execute_api_request integration tests passed!\n")
267+
268+
269+
asyncio.run(main())
270+
271+

0 commit comments

Comments
 (0)