Skip to content

Commit 1d03009

Browse files
committed
fix: refactor
1 parent 1450cff commit 1d03009

File tree

2 files changed

+195
-294
lines changed

2 files changed

+195
-294
lines changed

openfga_sdk/api/open_fga_api.py

Lines changed: 98 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,8 @@ async def _execute(
8888
) -> Any:
8989
"""Shared executor for all API endpoint methods.
9090
91-
Delegates to _execute_api_request_internal (or
92-
_execute_streamed_api_request_internal when _streaming=True) so all
93-
API calls share one unified code path.
91+
Delegates to the public execute_api_request / execute_streamed_api_request
92+
so all API calls share one unified code path.
9493
"""
9594
if options is None:
9695
options = {}
@@ -118,7 +117,7 @@ async def _execute(
118117
)
119118

120119
if options.get("_streaming", False):
121-
return self._execute_streamed_api_request_internal(
120+
return self.execute_streamed_api_request(
122121
operation_name=operation_name,
123122
method=method,
124123
path=path,
@@ -128,9 +127,10 @@ async def _execute(
128127
options=options,
129128
response_types_map=response_types_map,
130129
telemetry_attributes=telemetry_attributes,
130+
_skip_builder=True,
131131
)
132132

133-
return await self._execute_api_request_internal(
133+
return await self.execute_api_request(
134134
operation_name=operation_name,
135135
method=method,
136136
path=path,
@@ -151,16 +151,22 @@ async def execute_api_request(
151151
path: str,
152152
path_params: dict[str, str] | None = None,
153153
body: dict[str, Any] | list[Any] | str | bytes | None = None,
154-
query_params: dict[str, str | int | list[str | int]] | None = None,
154+
query_params: dict[str, str | int | list[str | int]] | list | None = None,
155155
headers: dict[str, str] | None = None,
156156
options: dict[str, Any] | None = None,
157-
) -> RawResponse:
157+
response_types_map: dict | None = None,
158+
telemetry_attributes: dict | None = None,
159+
_skip_builder: bool = False,
160+
) -> Any:
158161
"""
159162
Execute an arbitrary HTTP request to any OpenFGA API endpoint.
160163
161164
Useful for calling endpoints not yet wrapped by the SDK while
162165
still getting authentication, retries, and error handling.
163166
167+
When called directly by users, returns a RawResponse.
168+
When called internally with response_types_map, returns a deserialized typed model.
169+
164170
:param operation_name: Operation name for telemetry (e.g., "CustomCheck")
165171
:param method: HTTP method (GET, POST, PUT, DELETE, PATCH)
166172
:param path: API path, e.g. "/stores/{store_id}/my-endpoint".
@@ -170,92 +176,26 @@ async def execute_api_request(
170176
:param query_params: Query string parameters
171177
:param headers: Custom headers (SDK enforces Content-Type and Accept)
172178
:param options: Extra options e.g. {"retry_params": RetryParams(max_retry=3)}
173-
:return: RawResponse with status, headers, and body
179+
:param response_types_map: When provided, merge with common error types and
180+
return a deserialized typed model. When None, return RawResponse.
181+
:param telemetry_attributes: When provided, use as-is for telemetry.
182+
When None, build minimal defaults.
183+
:param _skip_builder: When True, path/headers/query_params are used as-is
184+
(already resolved by _execute). When False (default), run through
185+
ExecuteApiRequestBuilder.
186+
:return: RawResponse (public callers) or deserialized model (internal callers)
174187
"""
175-
return await self._execute_api_request_internal(
176-
operation_name=operation_name,
177-
method=method,
178-
path=path,
179-
path_params=path_params,
180-
body=body,
181-
query_params=query_params,
182-
headers=headers,
183-
options=options,
188+
from openfga_sdk.client.execute_api_request_builder import (
189+
ExecuteApiRequestBuilder,
190+
ResponseParser,
184191
)
192+
from openfga_sdk.client.models.raw_response import RawResponse
185193

186-
async def execute_streamed_api_request(
187-
self,
188-
*,
189-
operation_name: str,
190-
method: str,
191-
path: str,
192-
path_params: dict[str, str] | None = None,
193-
body: dict[str, Any] | list[Any] | str | bytes | None = None,
194-
query_params: dict[str, str | int | list[str | int]] | None = None,
195-
headers: dict[str, str] | None = None,
196-
options: dict[str, Any] | None = None,
197-
) -> AsyncIterator[dict[str, Any]]:
198-
"""
199-
Execute an arbitrary HTTP request to a streaming OpenFGA API endpoint.
200-
201-
Yields parsed JSON objects as they arrive. Use with async for:
202-
203-
async for chunk in api.execute_streamed_api_request(...):
204-
process(chunk)
205-
206-
:param operation_name: Operation name for telemetry (e.g., "StreamedListObjects")
207-
:param method: HTTP method (GET, POST, PUT, DELETE, PATCH)
208-
:param path: API path, e.g. "/stores/{store_id}/streamed-list-objects".
209-
:param path_params: Path parameter substitutions (URL-encoded automatically).
210-
All path parameters, including store_id, must be provided explicitly.
211-
:param body: Request body for POST/PUT/PATCH
212-
:param query_params: Query string parameters
213-
:param headers: Custom headers (SDK enforces Content-Type and Accept)
214-
:param options: Extra options e.g. {"retry_params": RetryParams(max_retry=3)}
215-
"""
216-
async for chunk in self._execute_streamed_api_request_internal(
217-
operation_name=operation_name,
218-
method=method,
219-
path=path,
220-
path_params=path_params,
221-
body=body,
222-
query_params=query_params,
223-
headers=headers,
224-
options=options,
225-
):
226-
yield chunk
227-
228-
async def _execute_streamed_api_request_internal(
229-
self,
230-
*,
231-
operation_name: str,
232-
method: str,
233-
path: str,
234-
path_params: dict[str, str] | None = None,
235-
body: dict[str, Any] | list[Any] | str | bytes | None = None,
236-
query_params=None,
237-
headers=None,
238-
options: dict[str, Any] | None = None,
239-
response_types_map: dict | None = None,
240-
telemetry_attributes: dict | None = None,
241-
_skip_builder: bool = False,
242-
) -> AsyncIterator[dict[str, Any]]:
243-
"""Implementation for streaming API requests.
244-
245-
When _skip_builder=True, query_params must already be a list of tuples
246-
and headers must already be a fully-built dict (used when called from _execute).
247-
When response_types_map is provided, it is merged with _COMMON_ERROR_RESPONSE_TYPES.
248-
When telemetry_attributes is provided, it is used as-is instead of building minimal defaults.
249-
"""
250194
if _skip_builder:
251195
resource_path = path
252196
query_params_list = query_params if query_params is not None else []
253197
final_headers = headers or {}
254198
else:
255-
from openfga_sdk.client.execute_api_request_builder import (
256-
ExecuteApiRequestBuilder,
257-
)
258-
259199
builder = ExecuteApiRequestBuilder(
260200
operation_name=operation_name,
261201
method=method,
@@ -272,6 +212,8 @@ async def _execute_streamed_api_request_internal(
272212
final_headers = builder.build_headers()
273213

274214
retry_params = options.get("retry_params") if options else None
215+
request_timeout = options.get("_request_timeout") if options else None
216+
async_req = options.get("async_req") if options else None
275217

276218
if telemetry_attributes is None:
277219
telemetry_attributes = {
@@ -287,62 +229,103 @@ async def _execute_streamed_api_request_internal(
287229
**self._COMMON_ERROR_RESPONSE_TYPES,
288230
**response_types_map,
289231
}
290-
else:
291-
merged_response_types_map = {}
232+
return await self.api_client.call_api(
233+
resource_path=resource_path,
234+
method=method.upper(),
235+
path_params={},
236+
query_params=query_params_list if query_params_list else [],
237+
header_params=final_headers,
238+
body=body,
239+
post_params=[],
240+
files={},
241+
response_types_map=merged_response_types_map,
242+
auth_settings=[],
243+
async_req=async_req,
244+
_return_http_data_only=True,
245+
_preload_content=True,
246+
_request_timeout=request_timeout,
247+
_retry_params=retry_params,
248+
collection_formats={},
249+
_oauth2_client=self._oauth2_client,
250+
_telemetry_attributes=telemetry_attributes,
251+
_streaming=False,
252+
)
292253

293-
stream = await self.api_client.call_api(
254+
# No response_types_map: public caller path → return RawResponse
255+
await self.api_client.call_api(
294256
resource_path=resource_path,
295257
method=method.upper(),
296258
query_params=query_params_list if query_params_list else None,
297259
header_params=final_headers,
298260
body=body,
299-
response_types_map=merged_response_types_map,
261+
response_types_map={},
300262
auth_settings=[],
301263
_return_http_data_only=True,
302264
_preload_content=True,
303265
_retry_params=retry_params,
304266
_oauth2_client=self._oauth2_client,
305267
_telemetry_attributes=telemetry_attributes,
306-
_streaming=True,
268+
_streaming=False,
307269
)
308270

309-
async for chunk in stream:
310-
yield chunk
271+
rest_response = getattr(self.api_client, "last_response", None)
272+
if rest_response is None:
273+
raise RuntimeError(
274+
f"No response for {method.upper()} {resource_path} "
275+
f"(operation: {operation_name})"
276+
)
277+
278+
return RawResponse(
279+
status=rest_response.status,
280+
headers=dict(rest_response.getheaders()),
281+
body=ResponseParser.parse_body(rest_response.data),
282+
)
311283

312-
async def _execute_api_request_internal(
284+
async def execute_streamed_api_request(
313285
self,
314286
*,
315287
operation_name: str,
316288
method: str,
317289
path: str,
318290
path_params: dict[str, str] | None = None,
319291
body: dict[str, Any] | list[Any] | str | bytes | None = None,
320-
query_params=None,
321-
headers=None,
292+
query_params: dict[str, str | int | list[str | int]] | list | None = None,
293+
headers: dict[str, str] | None = None,
322294
options: dict[str, Any] | None = None,
323295
response_types_map: dict | None = None,
324296
telemetry_attributes: dict | None = None,
325297
_skip_builder: bool = False,
326-
) -> Any:
327-
"""Implementation for execute_api_request (and _execute delegation).
328-
329-
When _skip_builder=True, query_params must already be a list of tuples
330-
and headers must already be a fully-built dict (used when called from _execute).
331-
When response_types_map is provided, it is merged with _COMMON_ERROR_RESPONSE_TYPES
332-
and the deserialized typed result from call_api is returned directly.
333-
When telemetry_attributes is provided, it is used as-is instead of building minimal defaults.
298+
) -> AsyncIterator[dict[str, Any]]:
334299
"""
335-
from openfga_sdk.client.execute_api_request_builder import (
336-
ExecuteApiRequestBuilder,
337-
ResponseParser,
338-
)
339-
from openfga_sdk.client.models.raw_response import RawResponse
300+
Execute an arbitrary HTTP request to a streaming OpenFGA API endpoint.
301+
302+
Yields parsed JSON objects as they arrive. Use with async for:
303+
304+
async for chunk in api.execute_streamed_api_request(...):
305+
process(chunk)
340306
307+
:param operation_name: Operation name for telemetry (e.g., "StreamedListObjects")
308+
:param method: HTTP method (GET, POST, PUT, DELETE, PATCH)
309+
:param path: API path, e.g. "/stores/{store_id}/streamed-list-objects".
310+
:param path_params: Path parameter substitutions (URL-encoded automatically).
311+
All path parameters, including store_id, must be provided explicitly.
312+
:param body: Request body for POST/PUT/PATCH
313+
:param query_params: Query string parameters
314+
:param headers: Custom headers (SDK enforces Content-Type and Accept)
315+
:param options: Extra options e.g. {"retry_params": RetryParams(max_retry=3)}
316+
:param response_types_map: When provided, merge with common error types.
317+
:param telemetry_attributes: When provided, use as-is for telemetry.
318+
:param _skip_builder: When True, path/headers/query_params are used as-is.
319+
"""
341320
if _skip_builder:
342321
resource_path = path
343322
query_params_list = query_params if query_params is not None else []
344323
final_headers = headers or {}
345324
else:
325+
from openfga_sdk.client.execute_api_request_builder import (
326+
ExecuteApiRequestBuilder,
327+
)
328+
346329
builder = ExecuteApiRequestBuilder(
347330
operation_name=operation_name,
348331
method=method,
@@ -359,8 +342,6 @@ async def _execute_api_request_internal(
359342
final_headers = builder.build_headers()
360343

361344
retry_params = options.get("retry_params") if options else None
362-
request_timeout = options.get("_request_timeout") if options else None
363-
async_req = options.get("async_req") if options else None
364345

365346
if telemetry_attributes is None:
366347
telemetry_attributes = {
@@ -376,58 +357,27 @@ async def _execute_api_request_internal(
376357
**self._COMMON_ERROR_RESPONSE_TYPES,
377358
**response_types_map,
378359
}
379-
# call_api returns a deserialized typed model when response_types_map is non-empty
380-
return await self.api_client.call_api(
381-
resource_path=resource_path,
382-
method=method.upper(),
383-
path_params={},
384-
query_params=query_params_list if query_params_list else [],
385-
header_params=final_headers,
386-
body=body,
387-
post_params=[],
388-
files={},
389-
response_types_map=merged_response_types_map,
390-
auth_settings=[],
391-
async_req=async_req,
392-
_return_http_data_only=True,
393-
_preload_content=True,
394-
_request_timeout=request_timeout,
395-
_retry_params=retry_params,
396-
collection_formats={},
397-
_oauth2_client=self._oauth2_client,
398-
_telemetry_attributes=telemetry_attributes,
399-
_streaming=False,
400-
)
360+
else:
361+
merged_response_types_map = {}
401362

402-
# No response_types_map: public execute_api_request path → return RawResponse
403-
await self.api_client.call_api(
363+
stream = await self.api_client.call_api(
404364
resource_path=resource_path,
405365
method=method.upper(),
406366
query_params=query_params_list if query_params_list else None,
407367
header_params=final_headers,
408368
body=body,
409-
response_types_map={},
369+
response_types_map=merged_response_types_map,
410370
auth_settings=[],
411371
_return_http_data_only=True,
412372
_preload_content=True,
413373
_retry_params=retry_params,
414374
_oauth2_client=self._oauth2_client,
415375
_telemetry_attributes=telemetry_attributes,
416-
_streaming=False,
376+
_streaming=True,
417377
)
418378

419-
rest_response = getattr(self.api_client, "last_response", None)
420-
if rest_response is None:
421-
raise RuntimeError(
422-
f"No response for {method.upper()} {resource_path} "
423-
f"(operation: {operation_name})"
424-
)
425-
426-
return RawResponse(
427-
status=rest_response.status,
428-
headers=dict(rest_response.getheaders()),
429-
body=ResponseParser.parse_body(rest_response.data),
430-
)
379+
async for chunk in stream:
380+
yield chunk
431381

432382
async def batch_check(self, body, **kwargs):
433383
"""Send a list of `check` operations in a single request

0 commit comments

Comments
 (0)