Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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