Skip to content

Conversation

@kcbiradar
Copy link

@kcbiradar kcbiradar commented Jan 15, 2026

This adds the capability to call any FGA endpoint.

What problem is being solved?
How is it being solved?
What changes are made to solve it?

References

closes

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

Release Notes

  • New Features

    • Added raw_request method to OpenFgaClient for making custom HTTP requests to OpenFGA endpoints
    • Introduced RawResponse type with status, headers, and parsed body data
  • Bug Fixes

    • Fixed HTTP header handling in API client responses
  • Documentation

    • Added "Calling Other Endpoints" section with usage examples and code samples
  • Tests

    • Added comprehensive test coverage for raw_request functionality

✏️ Tip: You can customize this high-level summary in your review settings.

@kcbiradar kcbiradar requested review from a team as code owners January 15, 2026 13:41
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Jan 15, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR introduces a new raw_request method to the OpenFgaClient (both async and sync variants) enabling arbitrary HTTP requests against OpenFGA endpoints. It includes a new RawResponse data model, updates ApiClient header handling, adds comprehensive test coverage, and documents the feature in the README.

Changes

Cohort / File(s) Summary
New RawResponse Model
openfga_sdk/client/models/raw_response.py, openfga_sdk/client/models/__init__.py
New dataclass RawResponse with status, headers, and body fields; includes json() and text() convenience methods for parsing response bodies. Exported in public API.
Core raw_request Implementation
openfga_sdk/client/client.py, openfga_sdk/sync/client/client.py
Added async and sync raw_request() methods enabling configurable HTTP requests with method, path, query/path params, headers, body, and operation_name. Includes parameter validation, path variable resolution (auto-fill store_id), URL encoding, query string building, JSON serialization, default headers, and integration with ApiClient for authentication and telemetry.
ApiClient Header Response Handling
openfga_sdk/api_client.py, openfga_sdk/sync/api_client.py
Changed header return value from response_data.headers to response_data.getheaders() when _return_http_data_only is False, altering how HTTP headers are exposed.
Telemetry Guard
openfga_sdk/telemetry/attributes.py
Added type guard isinstance(response.body, dict) before accessing body fields in TelemetryAttributes.fromResponse() to prevent errors with non-dict body types.
Test Coverage
test/client/client_test.py, test/sync/client/client_test.py
Comprehensive test suite covering POST/GET requests, path/query parameter handling, store_id auto-substitution, required field validation, default headers, URL encoding, list query params expansion, and RawResponse helper methods.
Documentation
README.md
New "Calling Other Endpoints" section documenting raw_request with usage scenarios and multiple Python examples (custom endpoints, response decoding, GET calls, path parameters).

Sequence Diagram(s)

sequenceDiagram
    participant Client as OpenFgaClient
    participant ApiClient as ApiClient
    participant HTTP as HTTP Layer
    participant Response as Response Parser

    Client->>Client: raw_request(method, path, params...)
    Client->>Client: Validate operation_name (required)
    Client->>Client: Resolve path params (auto-fill store_id)
    Client->>Client: URL-encode path params
    Client->>Client: Build query string
    Client->>Client: Serialize body (JSON if dict/list)
    Client->>Client: Set default headers (Content-Type, Accept)
    Client->>ApiClient: call_api(method, path, body, headers, query_params)
    ApiClient->>HTTP: Execute HTTP request
    HTTP->>ApiClient: Return HTTP response
    ApiClient->>Response: Parse response body
    Response->>Response: Try JSON decode, fallback to raw
    Response->>Client: Return RawResponse(status, headers, body)
    Client->>Client: Return RawResponse to caller
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • feat: improve error messaging #245: Modifies ApiClient.__call_api() header handling and exception propagation, overlapping with this PR's changes to the same ApiClient method.

Suggested reviewers

  • ttrzeng
  • daniel-jonathan
  • rhamzeh
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title 'feat: add raw requestor for calling arbitrary endpoints' directly and clearly summarizes the main change—introducing a raw_request method to call any FGA endpoint. It accurately reflects the primary objective of the pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot
Copy link

dosubot bot commented Jan 15, 2026

Related Documentation

Checked 6 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@SoulPancake SoulPancake changed the title feat/add-raw-request-method feat: add raw requestor for calling arbitrary endpoints Jan 15, 2026
@kcbiradar kcbiradar force-pushed the feat/add-raw-request-method branch from 840bc79 to f4dec14 Compare January 15, 2026 13:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

4-4: Malformed badge URL - missing closing parenthesis.

The Socket badge URL appears to be malformed. It's missing a closing parenthesis before the opening bracket for the link URL.

🔧 Suggested fix
-[![Socket Badge](https://badge.socket.dev/pypi/package/openfga-sdk/0.9.9](https://socket.dev/pypi/package/openfga-sdk)
+[![Socket Badge](https://badge.socket.dev/pypi/package/openfga-sdk/0.9.9)](https://socket.dev/pypi/package/openfga-sdk)
🤖 Fix all issues with AI agents
In `@openfga_sdk/sync/client/client.py`:
- Around line 1233-1234: The except block "except ApiException as e: raise" is
redundant and should be removed; locate the handler in
openfga_sdk/sync/client/client.py where ApiException is caught and simply delete
that except clause so the original ApiException will propagate naturally (leave
surrounding try/except structure and other exception handlers unchanged and
ensure indentation remains valid).
🧹 Nitpick comments (6)
openfga_sdk/client/models/raw_response.py (1)

49-63: Consider moving json import to module level.

The json module is imported inside the method body (lines 50 and 58). Since json is part of Python's standard library and always available, importing it at the module level (line 8-9 area) would be more idiomatic and slightly more efficient for repeated calls.

♻️ Suggested refactor

Add import at the top of the file:

 from dataclasses import dataclass
 from typing import Any
+import json

Then remove the inline imports in json() and text() methods.

openfga_sdk/sync/client/client.py (2)

1139-1141: Consider validating options["headers"] type before merging.

The code assumes options["headers"] is a dict when calling update(). For consistency with the set_heading_if_not_set helper (lines 102-103) which handles non-dict headers values, consider adding a type check.

♻️ Suggested defensive check
         request_headers = dict(headers) if headers else {}
         if options and options.get("headers"):
-            request_headers.update(options["headers"])
+            opt_headers = options.get("headers")
+            if isinstance(opt_headers, dict):
+                request_headers.update(opt_headers)

1196-1199: Header checks are case-sensitive but HTTP headers are case-insensitive.

The checks "Content-Type" not in request_headers won't match if a user provides "content-type" (lowercase). This could result in duplicate headers with different casing.

♻️ Suggested case-insensitive check
+        # Case-insensitive header check helper
+        request_headers_lower = {k.lower(): k for k in request_headers}
+        
-        if "Content-Type" not in request_headers:
+        if "content-type" not in request_headers_lower:
             request_headers["Content-Type"] = "application/json"
-        if "Accept" not in request_headers:
+        if "accept" not in request_headers_lower:
             request_headers["Accept"] = "application/json"
test/sync/client/client_test.py (1)

4151-4454: Good raw_request coverage; consider 2 small edge-case tests.

  1. Assert that custom headers passed to raw_request(..., headers=...) are actually forwarded (e.g., verify X-Experimental-Feature is present in the mocked call headers).
  2. Add a non-JSON response body case (e.g., content-type: text/plain) to validate RawResponse.text()/json() behavior when JSON parsing should fail.
openfga_sdk/client/client.py (2)

1140-1143: Define header precedence + coerce header values to strings.

Right now options["headers"] overrides the explicit headers argument (Line 1140-1143), and non-string values can slip in (your tests cover integer header values elsewhere). It’d be good to (a) document precedence, and (b) normalize values to str before sending.


1209-1234: Tighten telemetry + response typing.

  • TelemetryAttribute import inside the method is unused (Line 1211).
  • TelemetryAttributes.fga_client_request_method is set to operation_name.lower() (Line 1213-1214). Please confirm this attribute is meant to hold the operation name vs the HTTP verb (since you already have method).
  • Response parsing should allow top-level JSON arrays too (currently annotated as dict[str, Any], but json.loads(...) can return list[Any]). Consider widening the type and aligning RawResponse.body accordingly.

Also applies to: 1242-1265

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a67559 and 7d1ec7a.

📒 Files selected for processing (10)
  • README.md
  • openfga_sdk/api_client.py
  • openfga_sdk/client/client.py
  • openfga_sdk/client/models/__init__.py
  • openfga_sdk/client/models/raw_response.py
  • openfga_sdk/sync/api_client.py
  • openfga_sdk/sync/client/client.py
  • openfga_sdk/telemetry/attributes.py
  • test/client/client_test.py
  • test/sync/client/client_test.py
🧰 Additional context used
🧬 Code graph analysis (6)
openfga_sdk/client/models/__init__.py (1)
openfga_sdk/client/models/raw_response.py (1)
  • RawResponse (13-90)
openfga_sdk/sync/api_client.py (3)
openfga_sdk/rest.py (1)
  • getheaders (111-115)
openfga_sdk/sync/rest.py (1)
  • getheaders (111-115)
test/error_handling_test.py (1)
  • getheaders (31-32)
openfga_sdk/api_client.py (3)
openfga_sdk/rest.py (1)
  • getheaders (111-115)
openfga_sdk/sync/rest.py (1)
  • getheaders (111-115)
test/error_handling_test.py (1)
  • getheaders (31-32)
test/client/client_test.py (1)
openfga_sdk/client/models/raw_response.py (3)
  • RawResponse (13-90)
  • json (33-65)
  • text (67-90)
test/sync/client/client_test.py (2)
openfga_sdk/client/models/raw_response.py (3)
  • RawResponse (13-90)
  • json (33-65)
  • text (67-90)
openfga_sdk/rest.py (6)
  • RESTClientObject (128-461)
  • response (56-60)
  • response (63-67)
  • status (84-88)
  • status (91-95)
  • close (162-166)
openfga_sdk/client/client.py (6)
openfga_sdk/client/models/raw_response.py (2)
  • json (33-65)
  • RawResponse (13-90)
openfga_sdk/exceptions.py (2)
  • ApiException (118-298)
  • FgaValidationException (36-61)
openfga_sdk/sync/rest.py (5)
  • RESTResponse (27-125)
  • data (70-74)
  • data (77-81)
  • status (84-88)
  • status (91-95)
openfga_sdk/telemetry/attributes.py (3)
  • get (97-104)
  • TelemetryAttribute (14-16)
  • TelemetryAttributes (19-369)
openfga_sdk/api_client.py (2)
  • get_store_id (937-941)
  • update_params_for_auth (771-810)
openfga_sdk/sync/api_client.py (2)
  • get_store_id (937-941)
  • update_params_for_auth (771-810)
🔇 Additional comments (17)
openfga_sdk/client/models/__init__.py (1)

26-26: LGTM!

The RawResponse import and export follow the established pattern in this module. This correctly exposes the new model for downstream usage.

Also applies to: 49-49

openfga_sdk/api_client.py (1)

420-423: LGTM!

The change from response_data.headers to response_data.getheaders() ensures consistent header access and returns a proper dict[str, str] that aligns with the new RawResponse model's expected header format.

openfga_sdk/sync/api_client.py (1)

420-423: LGTM!

Consistent with the async client change, ensuring both sync and async variants use the same getheaders() method for header access.

openfga_sdk/telemetry/attributes.py (1)

298-302: Good defensive fix for handling non-dict response bodies.

The added isinstance(response.body, dict) check properly guards against AttributeError when body is bytes, str, or None - which is possible with the new RawResponse model where body type is bytes | str | dict[str, Any] | None.

README.md (2)

51-51: LGTM!

Good addition to the table of contents for the new feature section.


1264-1400: Comprehensive documentation for the new raw_request feature.

The documentation is well-structured with clear use cases and multiple examples covering:

  • Basic POST requests
  • Response handling (JSON parsing, accessing headers/status)
  • GET requests with query parameters
  • Path parameter substitution (explicit and automatic store_id)

The examples follow the existing documentation patterns in this README.

openfga_sdk/client/models/raw_response.py (1)

33-90: LGTM! The helper methods are well-implemented.

The json() and text() methods handle all expected body types (dict, str, bytes, None) with appropriate error handling and fallbacks. The UnicodeDecodeError handling with errors="replace" in text() is a good defensive pattern.

openfga_sdk/sync/client/client.py (3)

1-4: LGTM! Imports are appropriate for the new functionality.

The new imports (json, urllib.parse, RawResponse, ApiException, RESTResponse) are all necessary for the raw_request method implementation.

Also applies to: 38-38, 46-46, 77-77


1146-1167: LGTM! Path parameter handling is well-implemented.

The logic correctly:

  • Auto-fills store_id from configuration when not provided in path_params
  • URL-encodes path parameter values for safety
  • Validates that all placeholders are resolved before making the request

1243-1265: LGTM! Response body parsing handles all expected formats.

The parsing logic correctly handles JSON responses (both string and bytes) with appropriate fallbacks for non-JSON content. The final RawResponse construction properly captures status, headers, and body.

test/client/client_test.py (5)

28-28: LGTM! Import is correctly placed.

The RawResponse import is appropriately added alongside other model imports.


4170-4218: LGTM! Comprehensive test for POST request with body.

This test verifies:

  • RawResponse creation and properties (status, headers, body)
  • json() and text() helper methods work correctly
  • The API is called with correct method, path, body, query params, and headers

4330-4379: LGTM! Validation error tests cover required scenarios.

The tests properly verify that FgaValidationException is raised for:

  • Missing operation_name (required parameter)
  • Missing store_id when path contains {store_id}
  • Missing path parameters when placeholders exist

4381-4413: LGTM! List query parameter expansion test.

This test verifies that list values in query_params are correctly expanded into multiple key-value pairs (e.g., {"ids": ["id1", "id2", "id3"]} becomes [("ids", "id1"), ("ids", "id2"), ("ids", "id3")]).


4444-4475: LGTM! URL encoding test verifies special character handling.

The test confirms that path parameters containing spaces and special characters (value with spaces & special chars) are properly URL-encoded to value%20with%20spaces%20%26%20special%20chars.

test/sync/client/client_test.py (1)

26-26: RawResponse import looks fine.

openfga_sdk/client/client.py (1)

3-6: No issues with the new imports.

Also applies to: 39-40, 46-51, 76-76

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@kcbiradar
Copy link
Author

@rhamzeh @SoulPancake, please review and suggest if any changes are required.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a raw_request method to the OpenFGA Python SDK, enabling developers to call arbitrary FGA endpoints that may not yet be wrapped by the SDK. This is useful for calling experimental features, custom endpoints, or new API features in older SDK versions.

Changes:

  • Added RawResponse dataclass with status, headers, body, and helper methods (json(), text())
  • Implemented raw_request() method in both async and sync clients with path parameter substitution, query parameter handling, and automatic store_id resolution
  • Fixed API client header handling to use getheaders() for proper dict conversion

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
openfga_sdk/client/models/raw_response.py New RawResponse model with status, headers, body, and utility methods
openfga_sdk/client/client.py Async raw_request implementation with URL encoding, query params, and telemetry
openfga_sdk/sync/client/client.py Sync version of raw_request with identical logic
openfga_sdk/api_client.py Fixed header handling to return dict from getheaders()
openfga_sdk/sync/api_client.py Fixed header handling in sync client
openfga_sdk/telemetry/attributes.py Added type check for response.body before dict operations
openfga_sdk/client/models/init.py Exported RawResponse in module
test/client/client_test.py Comprehensive async tests for raw_request
test/sync/client/client_test.py Comprehensive sync tests for raw_request
README.md Documentation with usage examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@SoulPancake
Copy link
Member

Thanks for your PR @kcbiradar
Bunch of failing tests, can you have a look once?

@kcbiradar kcbiradar force-pushed the feat/add-raw-request-method branch from b1adb8c to 3f85dfa Compare January 17, 2026 10:19
@kcbiradar
Copy link
Author

@SoulPancake Thanks for reviewing, updated failing testcases. Please can you re-review once?

@codecov-commenter
Copy link

codecov-commenter commented Jan 17, 2026

Codecov Report

❌ Patch coverage is 73.68421% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.22%. Comparing base (8cc5f26) to head (6188d9e).

Files with missing lines Patch % Lines
openfga_sdk/client/client.py 73.75% 21 Missing ⚠️
openfga_sdk/sync/client/client.py 73.75% 21 Missing ⚠️
openfga_sdk/client/models/raw_response.py 71.42% 8 Missing ⚠️

❌ Your project status has failed because the head coverage (71.22%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #252      +/-   ##
==========================================
+ Coverage   71.17%   71.22%   +0.05%     
==========================================
  Files         137      138       +1     
  Lines       11100    11289     +189     
==========================================
+ Hits         7900     8041     +141     
- Misses       3200     3248      +48     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kcbiradar
Copy link
Author

kcbiradar commented Jan 18, 2026

@SoulPancake, any changes needed here?

@kcbiradar
Copy link
Author

@SoulPancake Thanks for reviewing, the requested changes are updated

@kcbiradar kcbiradar requested a review from SoulPancake January 18, 2026 08:36
@kcbiradar
Copy link
Author

@SoulPancake please re-review once

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@kcbiradar
Copy link
Author

kcbiradar commented Jan 19, 2026

@SoulPancake updated the requested changes. Please re-review once

@kcbiradar kcbiradar requested a review from SoulPancake January 19, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add raw request method to Python SDK for calling arbitrary API endpoints

3 participants