Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fopenfga%2Fpython-sdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fopenfga%2Fpython-sdk?ref=badge_shield)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/openfga/python-sdk/badge)](https://securityscorecards.dev/viewer/?uri=github.com/openfga/python-sdk)
[![Join our community](https://img.shields.io/badge/slack-cncf_%23openfga-40abb8.svg?logo=slack)](https://openfga.dev/community)
[![X](https://img.shields.io/twitter/follow/openfga?color=%23179CF0&logo=twitter&style=flat-square "@openfga on Twitter")](https://x.com/openfga)
[![X](https://img.shields.io/twitter/follow/openfga?color=%23179CF0&logo=x&style=flat-square "@openfga on X")](https://x.com/openfga)

This is an autogenerated python SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api).

Expand Down Expand Up @@ -64,7 +64,7 @@ OpenFGA is designed to make it easy for application builders to model their perm

- [OpenFGA Documentation](https://openfga.dev/docs)
- [OpenFGA API Documentation](https://openfga.dev/api/service)
- [Twitter](https://twitter.com/openfga)
- [X](https://x.com/openfga)
- [OpenFGA Community](https://openfga.dev/community)
- [Zanzibar Academy](https://zanzibar.academy)
- [Google's Zanzibar Paper (2019)](https://research.google/pubs/pub48190/)
Expand Down
3 changes: 1 addition & 2 deletions openfga_sdk/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ async def __call_api(
start = float(time.time())

# header parameters
header_params = header_params or {}
header_params.update(self.default_headers)
header_params = {**self.default_headers, **(header_params or {})}
if self.cookie:
header_params["Cookie"] = self.cookie
if header_params:
Expand Down
2 changes: 1 addition & 1 deletion openfga_sdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def set_heading_if_not_set(
_options["headers"] = {}

if type(_options["headers"]) is dict:
if type(_options["headers"].get(name)) not in [int, str]:
if _options["headers"].get(name) is None:
_options["headers"][name] = value

return _options
Expand Down
3 changes: 1 addition & 2 deletions openfga_sdk/sync/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ def __call_api(
start = float(time.time())

# header parameters
header_params = header_params or {}
header_params.update(self.default_headers)
header_params = {**self.default_headers, **(header_params or {})}
if self.cookie:
header_params["Cookie"] = self.cookie
if header_params:
Expand Down
2 changes: 1 addition & 1 deletion openfga_sdk/sync/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def set_heading_if_not_set(
_options["headers"] = {}

if type(_options["headers"]) is dict:
if type(_options["headers"].get(name)) not in [int, str]:
if _options["headers"].get(name) is None:
_options["headers"][name] = value

return _options
Expand Down
117 changes: 117 additions & 0 deletions test/api/open_fga_api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 +2048,123 @@ async def test_read_with_type_only_object(self, mock_request):
)
await api_client.close()

@patch.object(rest.RESTClientObject, "request")
async def test_check_custom_header_override_default_header(self, mock_request):
"""Test case for per-request custom header overriding default header

Per-request custom headers should override default headers with the same name
"""

# First, mock the response
response_body = '{"allowed": true}'
mock_request.return_value = mock_response(response_body, 200)

configuration = self.configuration
configuration.store_id = store_id
async with openfga_sdk.ApiClient(configuration) as api_client:
# Set a default header
api_client.set_default_header("X-Custom-Header", "default-value")
api_instance = open_fga_api.OpenFgaApi(api_client)
body = CheckRequest(
tuple_key=TupleKey(
object="document:2021-budget",
relation="reader",
user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
),
)
# Make request with per-request custom header that should override the default
api_response = await api_instance.check(
body=body,
_headers={"X-Custom-Header": "per-request-value"},
)
self.assertIsInstance(api_response, CheckResponse)
self.assertTrue(api_response.allowed)
# Make sure the API was called with the per-request header value, not the default
expected_headers = urllib3.response.HTTPHeaderDict(
{
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "openfga-sdk python/0.9.6",
"X-Custom-Header": "per-request-value", # Should be the per-request value
}
)
mock_request.assert_called_once_with(
"POST",
"http://api.fga.example/stores/01H0H015178Y2V4CX10C2KGHF4/check",
headers=expected_headers,
query_params=[],
post_params=[],
body={
"tuple_key": {
"object": "document:2021-budget",
"relation": "reader",
"user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
}
},
_preload_content=ANY,
_request_timeout=None,
)

@patch.object(rest.RESTClientObject, "request")
async def test_check_per_request_header_and_default_header_coexist(
self, mock_request
):
"""Test case for per-request custom header and default header coexisting

Per-request custom headers should be merged with default headers
"""

# First, mock the response
response_body = '{"allowed": true}'
mock_request.return_value = mock_response(response_body, 200)

configuration = self.configuration
configuration.store_id = store_id
async with openfga_sdk.ApiClient(configuration) as api_client:
# Set a default header
api_client.set_default_header("X-Default-Header", "default-value")
api_instance = open_fga_api.OpenFgaApi(api_client)
body = CheckRequest(
tuple_key=TupleKey(
object="document:2021-budget",
relation="reader",
user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
),
)
# Make request with per-request custom header (different from default)
api_response = await api_instance.check(
body=body,
_headers={"X-Per-Request-Header": "per-request-value"},
)
self.assertIsInstance(api_response, CheckResponse)
self.assertTrue(api_response.allowed)
# Make sure both headers are present in the request
expected_headers = urllib3.response.HTTPHeaderDict(
{
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "openfga-sdk python/0.9.6",
"X-Default-Header": "default-value", # Default header preserved
"X-Per-Request-Header": "per-request-value", # Per-request header added
}
)
mock_request.assert_called_once_with(
"POST",
"http://api.fga.example/stores/01H0H015178Y2V4CX10C2KGHF4/check",
headers=expected_headers,
query_params=[],
post_params=[],
body={
"tuple_key": {
"object": "document:2021-budget",
"relation": "reader",
"user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
}
},
_preload_content=ANY,
_request_timeout=None,
)


if __name__ == "__main__":
unittest.main()
Loading