Skip to content

Commit b407f56

Browse files
feat: add X-Glean headers for experimental features and deprecation testing
- Add XGlean beforeRequest hook that sets X-Glean-Exclude-Deprecated-After and X-Glean-Experimental headers - Introduce new SDK options exclude_deprecated_after and include_experimental with corresponding environment variable support - Add documentation for testing experimental features and deprecation testing - Add comprehensive test suite for the XGlean hook
1 parent 56b3b86 commit b407f56

File tree

6 files changed

+403
-0
lines changed

6 files changed

+403
-0
lines changed

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Remember that each namespace requires its own authentication token type as descr
5656
* [Custom HTTP Client](#custom-http-client)
5757
* [Resource Management](#resource-management)
5858
* [Debugging](#debugging)
59+
* [Experimental Features and Deprecation Testing](#experimental-features-and-deprecation-testing)
5960
* [Development](#development)
6061
* [Maturity](#maturity)
6162
* [Contributions](#contributions)
@@ -960,6 +961,62 @@ s = Glean(debug_logger=logging.getLogger("glean.api_client"))
960961
You can also enable a default debug logger by setting an environment variable `GLEAN_DEBUG` to true.
961962
<!-- End Debugging [debug] -->
962963

964+
## Experimental Features and Deprecation Testing
965+
966+
The SDK provides options to test upcoming API changes before they become the default behavior. This is useful for:
967+
968+
- **Testing experimental features** before they are generally available
969+
- **Preparing for deprecations** by excluding deprecated endpoints ahead of their removal
970+
971+
### Configuration Options
972+
973+
You can configure these options either via environment variables or SDK constructor options:
974+
975+
#### Using Environment Variables
976+
977+
```python
978+
import os
979+
980+
# Set environment variables before initializing the SDK
981+
os.environ["X_GLEAN_EXCLUDE_DEPRECATED_AFTER"] = "2026-10-15"
982+
os.environ["X_GLEAN_INCLUDE_EXPERIMENTAL"] = "true"
983+
984+
from glean.api_client import Glean
985+
986+
glean = Glean(
987+
api_token=os.environ.get("GLEAN_API_TOKEN", ""),
988+
instance=os.environ.get("GLEAN_INSTANCE", ""),
989+
)
990+
```
991+
992+
#### Using SDK Constructor Options
993+
994+
```python
995+
import os
996+
997+
from glean.api_client import Glean
998+
999+
glean = Glean(
1000+
api_token=os.environ.get("GLEAN_API_TOKEN", ""),
1001+
instance=os.environ.get("GLEAN_INSTANCE", ""),
1002+
exclude_deprecated_after="2026-10-15",
1003+
include_experimental=True,
1004+
)
1005+
```
1006+
1007+
### Option Reference
1008+
1009+
| Option | Environment Variable | Type | Description |
1010+
| ------ | -------------------- | ---- | ----------- |
1011+
| `exclude_deprecated_after` | `X_GLEAN_EXCLUDE_DEPRECATED_AFTER` | `str` (date) | Exclude API endpoints that will be deprecated after this date (format: `YYYY-MM-DD`). Use this to test your integration against upcoming deprecations. |
1012+
| `include_experimental` | `X_GLEAN_INCLUDE_EXPERIMENTAL` | `bool` | When `True`, enables experimental API features that are not yet generally available. Use this to preview and test new functionality. |
1013+
1014+
> [!NOTE]
1015+
> Environment variables take precedence over SDK constructor options when both are set.
1016+
1017+
> [!WARNING]
1018+
> Experimental features may change or be removed without notice. Do not rely on experimental features in production environments.
1019+
9631020
<!-- Placeholder for Future Speakeasy SDK Sections -->
9641021

9651022
# Development

src/glean/api_client/_hooks/registration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .types import Hooks
22
from .multipart_fix_hook import MultipartFileFieldFixHook
33
from .agent_file_upload_error_hook import AgentFileUploadErrorHook
4+
from .x_glean import XGlean
45

56

67
# This file is only ever generated once on the first generation and then is free to be modified.
@@ -19,3 +20,6 @@ def init_hooks(hooks: Hooks):
1920

2021
# Register hook to provide helpful error messages for agent file upload issues
2122
hooks.register_after_error_hook(AgentFileUploadErrorHook())
23+
24+
# Register hook for X-Glean headers (experimental features and deprecation testing)
25+
hooks.register_before_request_hook(XGlean())
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""Hook to set X-Glean headers for experimental features and deprecation testing."""
2+
3+
import os
4+
from typing import Optional, Union
5+
import httpx
6+
from glean.api_client._hooks.types import BeforeRequestContext, BeforeRequestHook
7+
8+
9+
def _get_first_value(
10+
env_value: Optional[str],
11+
config_value: Optional[str],
12+
) -> Optional[str]:
13+
"""Get the first non-empty value from the provided arguments.
14+
15+
Environment variables take precedence over SDK constructor options.
16+
"""
17+
if env_value:
18+
return env_value
19+
if config_value:
20+
return config_value
21+
return None
22+
23+
24+
class XGlean(BeforeRequestHook):
25+
"""
26+
Hook that sets X-Glean headers for experimental features and deprecation testing.
27+
28+
This hook adds the following headers when configured:
29+
- X-Glean-Exclude-Deprecated-After: Excludes API endpoints deprecated after this date
30+
- X-Glean-Experimental: Enables experimental API features
31+
32+
Configuration can be done via environment variables or SDK constructor options.
33+
Environment variables take precedence over SDK constructor options.
34+
"""
35+
36+
def before_request(
37+
self, hook_ctx: BeforeRequestContext, request: httpx.Request
38+
) -> Union[httpx.Request, Exception]:
39+
"""
40+
Add X-Glean headers to the request based on configuration.
41+
42+
Args:
43+
hook_ctx: Context containing SDK configuration
44+
request: The HTTP request being made
45+
46+
Returns:
47+
The modified request with X-Glean headers added
48+
"""
49+
# Get deprecated value - env var takes precedence
50+
deprecated_value = _get_first_value(
51+
os.environ.get("X_GLEAN_EXCLUDE_DEPRECATED_AFTER"),
52+
hook_ctx.config.exclude_deprecated_after,
53+
)
54+
55+
# Get experimental value - env var takes precedence
56+
config_experimental = (
57+
"true" if hook_ctx.config.include_experimental is True else None
58+
)
59+
experimental_value = _get_first_value(
60+
os.environ.get("X_GLEAN_INCLUDE_EXPERIMENTAL"),
61+
config_experimental,
62+
)
63+
64+
# Create new headers dict with existing headers
65+
new_headers = dict(request.headers)
66+
67+
if deprecated_value:
68+
new_headers["X-Glean-Exclude-Deprecated-After"] = deprecated_value
69+
70+
if experimental_value:
71+
new_headers["X-Glean-Experimental"] = experimental_value
72+
73+
# Return new request with updated headers
74+
return httpx.Request(
75+
method=request.method,
76+
url=request.url,
77+
headers=new_headers,
78+
content=request.content,
79+
extensions=request.extensions,
80+
)

src/glean/api_client/sdk.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def __init__(
6161
retry_config: OptionalNullable[RetryConfig] = UNSET,
6262
timeout_ms: Optional[int] = None,
6363
debug_logger: Optional[Logger] = None,
64+
exclude_deprecated_after: Optional[str] = None,
65+
include_experimental: Optional[bool] = None,
6466
) -> None:
6567
r"""Instantiates the SDK configuring it with the provided parameters.
6668
@@ -73,6 +75,8 @@ def __init__(
7375
:param async_client: The Async HTTP client to use for all asynchronous methods
7476
:param retry_config: The retry configuration to use for all supported methods
7577
:param timeout_ms: Optional request timeout applied to each operation in milliseconds
78+
:param exclude_deprecated_after: Exclude API endpoints deprecated after this date (YYYY-MM-DD)
79+
:param include_experimental: When True, enables experimental API features
7680
"""
7781
client_supplied = True
7882
if client is None:
@@ -125,6 +129,8 @@ def __init__(
125129
retry_config=retry_config,
126130
timeout_ms=timeout_ms,
127131
debug_logger=debug_logger,
132+
exclude_deprecated_after=exclude_deprecated_after,
133+
include_experimental=include_experimental,
128134
),
129135
parent_ref=self,
130136
)

src/glean/api_client/sdkconfiguration.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ class SDKConfiguration:
3939
user_agent: str = __user_agent__
4040
retry_config: OptionalNullable[RetryConfig] = Field(default_factory=lambda: UNSET)
4141
timeout_ms: Optional[int] = None
42+
exclude_deprecated_after: Optional[str] = None
43+
"""
44+
Exclude API endpoints that will be deprecated after this date.
45+
Use this to test your integration against upcoming deprecations.
46+
Format: YYYY-MM-DD (e.g., '2026-10-15')
47+
48+
More information: https://developers.glean.com/deprecations/overview
49+
"""
50+
include_experimental: Optional[bool] = None
51+
"""
52+
When True, enables experimental API features that are not yet generally available.
53+
Use this to preview and test new functionality.
54+
"""
4255

4356
def get_server_details(self) -> Tuple[str, Dict[str, str]]:
4457
if self.server_url is not None and self.server_url:

0 commit comments

Comments
 (0)