Skip to content

Conversation

@evansims
Copy link
Contributor

@evansims evansims commented Oct 3, 2025

This PR addresses a bug in which, when calling a Client API method with custom headers, those headers may not be sent as expected. An issue related to the way header merging was occurring could result in custom headers being dropped.

Before:

# User sets a default header
client.set_default_header("X-Custom-Header", "default-value")

# User makes a request with per-request header
response = client.check(body, _headers={"X-Custom-Header": "per-request-value"})

# Old code would NOT override because "default-value" is type str
# Result: Request uses "default-value" (wrong)

After:

# User sets a default header
client.set_default_header("X-Custom-Header", "default-value")

# User makes a request with per-request header
response = client.check(body, _headers={"X-Custom-Header": "per-request-value"})

# New code checks if header is None, sees it's already set to "per-request-value"
# Result: Request uses "per-request-value" (correct)

References

Builds → openfga/python-sdk#230

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

  • New Features
    • Added a helper to set a request header only if it’s missing, without overwriting existing values.
  • Bug Fixes
    • Improved header merging so default headers are always included and per‑request headers correctly override defaults when keys match.
    • Ensured per‑request and default headers can coexist predictably across async and sync clients.
  • Tests
    • Added comprehensive tests validating header override, coexistence, and preservation across operations (check, write, expand, list, batch) for both async and sync clients.

@evansims evansims added the bug Something isn't working label Oct 3, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

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.

Walkthrough

Header composition logic updated to merge default and per-request headers with per-request precedence in both async and sync clients. The set_heading_if_not_set behavior changed to only set a header when it is missing. Extensive async and sync tests were added to validate header merging, overrides, and the new helper’s behavior.

Changes

Cohort / File(s) Summary
Header merge in API clients
config/clients/python/template/src/api_client.py.mustache, config/clients/python/template/src/sync/api_client.py.mustache
Replace in-place updates with merged dict: header_params = {**self.default_headers, **(header_params or {})} to include defaults and allow per-request overrides; rest of flow unchanged.
Helper behavior: set_heading_if_not_set
config/clients/python/template/src/client/client.py.mustache, config/clients/python/template/src/sync/client/client.py.mustache
Change condition to set header only when _options["headers"].get(name) is None; previously overwrote based on non-int/non-str type. Public export of helper implied by tests.
Async API tests for header precedence/merge
config/clients/python/template/test/api_test.py.mustache
Add tests verifying per-request header overrides default and that default and per-request headers coexist; includes duplicated insertion of similar tests.
Sync API tests for header precedence/merge
config/clients/python/template/test/sync/api_test.py.mustache
Add two tests validating override and coexistence of default and per-request headers in sync flow.
Async client helper tests and exports
config/clients/python/template/test/client/client_test.py.mustache
Add broad tests for set_heading_if_not_set (creation, no-overwrite, preservation, type handling, multiple API interactions). Import updated to expose the helper.
Sync client helper tests and exports
config/clients/python/template/test/sync/client/client_test.py.mustache
Add analogous tests for sync helper behavior and header propagation; module import updated to include helper.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant Client as OpenFgaClient
  participant API as ApiClient
  participant HTTP as RESTClientObject

  App->>Client: call operation(options with _headers?)
  Client->>Client: set_heading_if_not_set(options, name, value)\n(only if missing)
  Client->>API: invoke API method with options.headers
  API->>API: header_params = {**default_headers, **(options.headers or {})}
  API->>HTTP: request(method, url, headers=header_params)
  HTTP-->>API: response
  API-->>Client: parsed response
  Client-->>App: result
  note over API,HTTP: Per-request headers take precedence over defaults
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly indicates that this PR fixes an issue with custom header precedence in the Python SDK and aligns with the conventional commit format. It directly reflects the primary change of ensuring per-request headers override default headers without adding noise. It is concise and clear for teammates scanning the commit history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

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.

@evansims evansims marked this pull request as ready for review October 3, 2025 21:10
@evansims evansims requested a review from a team as a code owner October 3, 2025 21:10
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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7101069 and 18b61c5.

📒 Files selected for processing (8)
  • config/clients/python/template/src/api_client.py.mustache (1 hunks)
  • config/clients/python/template/src/client/client.py.mustache (1 hunks)
  • config/clients/python/template/src/sync/api_client.py.mustache (1 hunks)
  • config/clients/python/template/src/sync/client/client.py.mustache (1 hunks)
  • config/clients/python/template/test/api_test.py.mustache (1 hunks)
  • config/clients/python/template/test/client/client_test.py.mustache (2 hunks)
  • config/clients/python/template/test/sync/api_test.py.mustache (1 hunks)
  • config/clients/python/template/test/sync/client/client_test.py.mustache (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
config/**/*.mustache

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Validate mustache syntax and variable references across all template files, including CHANGELOG.md.mustache

Files:

  • config/clients/python/template/src/client/client.py.mustache
  • config/clients/python/template/src/sync/client/client.py.mustache
  • config/clients/python/template/test/api_test.py.mustache
  • config/clients/python/template/test/sync/client/client_test.py.mustache
  • config/clients/python/template/test/sync/api_test.py.mustache
  • config/clients/python/template/test/client/client_test.py.mustache
  • config/clients/python/template/src/api_client.py.mustache
  • config/clients/python/template/src/sync/api_client.py.mustache
config/**/*.{json,mustache}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Never hardcode API keys or credentials in configuration or template files

Files:

  • config/clients/python/template/src/client/client.py.mustache
  • config/clients/python/template/src/sync/client/client.py.mustache
  • config/clients/python/template/test/api_test.py.mustache
  • config/clients/python/template/test/sync/client/client_test.py.mustache
  • config/clients/python/template/test/sync/api_test.py.mustache
  • config/clients/python/template/test/client/client_test.py.mustache
  • config/clients/python/template/src/api_client.py.mustache
  • config/clients/python/template/src/sync/api_client.py.mustache
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test-java-sdk
🔇 Additional comments (2)
config/clients/python/template/test/sync/client/client_test.py.mustache (2)

3269-3397: Excellent test coverage for the header helper function.

The 15 unit tests for set_heading_if_not_set provide comprehensive validation of the bug fix and edge cases:

  • Core bug fix validation (line 3300): ensures existing headers are NOT overridden
  • Proper handling of missing/empty options and headers
  • Edge cases: non-dict headers, unicode, special characters, case sensitivity
  • Mutation behavior: preserves existing values and other headers

The test suite clearly demonstrates the intended behavior and will prevent regressions.


3399-3594: Comprehensive integration test coverage for custom headers.

The 8 integration tests validate that custom headers work correctly across all major API methods:

  • Single API calls (check, write, expand, list_objects, list_users)
  • Batch operations (client_batch_check)
  • Multiple sequential calls with different headers

This thorough coverage ensures that the header precedence fix works end-to-end from the client layer through to the REST client, preventing regressions across the entire API surface.

@rhamzeh rhamzeh added this pull request to the merge queue Oct 3, 2025
Merged via the queue into main with commit 8f0d2a6 Oct 3, 2025
19 checks passed
@rhamzeh rhamzeh deleted the fix/python/custom-header-precedence branch October 3, 2025 22:31
@dyeam0 dyeam0 linked an issue Oct 23, 2025 that may be closed by this pull request
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request] Add support for per-request custom HTTP headers in SDK API calls

3 participants