Skip to content

Commit 0f812e4

Browse files
authored
feat: add headers configuration property (#233)
2 parents 35ca07f + 2ba1362 commit 0f812e4

File tree

8 files changed

+691
-5
lines changed

8 files changed

+691
-5
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ async def main():
204204

205205
#### Default Headers
206206

207-
You can set default headers that will be sent with every request by accessing the API client and using the `set_default_header` method:
207+
You can configure default headers that will be sent with every request by passing them to the `ClientConfiguration`:
208208

209209
```python
210210
from openfga_sdk import ClientConfiguration, OpenFgaClient
@@ -215,13 +215,13 @@ async def main():
215215
api_url=FGA_API_URL,
216216
store_id=FGA_STORE_ID,
217217
authorization_model_id=FGA_MODEL_ID,
218+
headers={
219+
"X-Custom-Header": "default-value",
220+
"X-Request-Source": "my-app",
221+
},
218222
)
219223

220224
async with OpenFgaClient(configuration) as fga_client:
221-
# Set default headers that will be sent with every request
222-
fga_client._api_client.set_default_header("X-Custom-Header", "default-value")
223-
fga_client._api_client.set_default_header("X-Request-Source", "my-app")
224-
225225
api_response = await fga_client.read_authorization_models()
226226
return api_response
227227
```

openfga_sdk/client/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ def __init__(self, configuration: ClientConfiguration):
168168
self._api_client = ApiClient(configuration)
169169
self._api = OpenFgaApi(self._api_client)
170170

171+
# Set default headers from configuration
172+
if configuration.headers:
173+
for header_name, header_value in configuration.headers.items():
174+
self._api_client.set_default_header(header_name, header_value)
175+
171176
async def __aenter__(self):
172177
return self
173178

openfga_sdk/client/configuration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def __init__(
5353
]
5454
| None
5555
) = None,
56+
headers: dict[str, str] | None = None,
5657
):
5758
super().__init__(
5859
api_scheme,
@@ -64,6 +65,7 @@ def __init__(
6465
api_url=api_url,
6566
timeout_millisec=timeout_millisec,
6667
telemetry=telemetry,
68+
headers=headers,
6769
)
6870
self._authorization_model_id = authorization_model_id
6971

openfga_sdk/configuration.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def __init__(
202202
| None
203203
) = None,
204204
timeout_millisec: int | None = None,
205+
headers: dict[str, str] | None = None,
205206
):
206207
"""Constructor"""
207208
self._url = api_url
@@ -326,6 +327,10 @@ def __init__(
326327
"""Telemetry configuration
327328
"""
328329

330+
self._headers = headers or {}
331+
"""Default headers to be sent with every request
332+
"""
333+
329334
def __deepcopy__(self, memo):
330335
cls = self.__class__
331336
result = cls.__new__(cls)
@@ -656,6 +661,17 @@ def is_valid(self):
656661
f"timeout_millisec not within reasonable range (0,60000), {self._timeout_millisec}"
657662
)
658663

664+
if self._headers is not None:
665+
for key, value in self._headers.items():
666+
if not isinstance(key, str):
667+
raise FgaValidationException(
668+
f"header keys must be strings, got {type(key).__name__} for key {key}"
669+
)
670+
if not isinstance(value, str):
671+
raise FgaValidationException(
672+
f"header values must be strings, got {type(value).__name__} for key '{key}'"
673+
)
674+
659675
@property
660676
def api_scheme(self):
661677
"""Return connection is https or http."""
@@ -740,3 +756,31 @@ def timeout_millisec(self, value):
740756
Update timeout milliseconds
741757
"""
742758
self._timeout_millisec = value
759+
760+
@property
761+
def headers(self) -> dict[str, str]:
762+
"""
763+
Return default headers to be sent with every request.
764+
765+
Headers are key-value pairs that will be included in all API requests.
766+
Common use cases include correlation IDs, API versioning, and tenant identification.
767+
"""
768+
return self._headers
769+
770+
@headers.setter
771+
def headers(self, value: dict[str, str] | None) -> None:
772+
"""
773+
Update default headers to be sent with every request.
774+
775+
Args:
776+
value: Dictionary of header names to values, or None to clear headers.
777+
Both keys and values must be strings.
778+
779+
Raises:
780+
FgaValidationException: If value is not a dict or None.
781+
"""
782+
if value is not None and not isinstance(value, dict):
783+
raise FgaValidationException(
784+
f"headers must be a dict or None, got {type(value).__name__}"
785+
)
786+
self._headers = value or {}

openfga_sdk/sync/client/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ def __init__(self, configuration: ClientConfiguration) -> None:
169169
self._api_client = ApiClient(configuration)
170170
self._api = OpenFgaApi(self._api_client)
171171

172+
# Set default headers from configuration
173+
if configuration.headers:
174+
for header_name, header_value in configuration.headers.items():
175+
self._api_client.set_default_header(header_name, header_value)
176+
172177
def __enter__(self):
173178
return self
174179

0 commit comments

Comments
 (0)