Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds per-request custom HTTP header support across the SDK: new Headers on request option models, optional headers parameter on API methods, header validation in configuration, and header merging in ApiClient. Tests are expanded to validate reserved headers, overrides, error cases, and concurrency. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App as Application
participant Client as OpenFgaClient
participant API as OpenFgaApi
participant AC as ApiClient
participant HTTP as HttpClient
App->>Client: Call (e.g., Check) with Options.Headers
Client->>Client: ExtractHeaders(options) + ValidateHeaders
Client->>API: Call method(..., headers)
API->>AC: SendRequestAsync(..., perRequestHeaders=headers)
AC->>AC: BuildHeaders(oauthToken, perRequestHeaders)\n- Merge, per-request overrides token header if set\n- Omit reserved defaults from user headers
AC->>HTTP: Execute request with merged headers
HTTP-->>AC: Response
AC-->>API: Parsed result
API-->>Client: Result
Client-->>App: Result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
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. Comment |
…tainsKey Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
|
I will have a follow-up PR with documentation coverage for this feature. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
src/OpenFga.Sdk/Client/ClientConfiguration.cs (1)
115-151: Robust header validation; consider key CR/LF check and minor hardeningThe reserved-set and value CR/LF checks are solid. Two small hardening tweaks:
- Also reject CR/LF in header names (defense-in-depth).
- Optionally use StringComparer.OrdinalIgnoreCase in any downstream merge dictionaries to avoid casing surprises.
Example tweak:
- foreach (var header in headers) { - if (string.IsNullOrWhiteSpace(header.Key)) { + foreach (var header in headers) { + if (string.IsNullOrWhiteSpace(header.Key) || header.Key.Contains("\r") || header.Key.Contains("\n")) { throw new ArgumentException("Header name cannot be null, empty, or whitespace.", paramName); }src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs (3)
70-90: Test helper locks tests to _config; allow passing a custom configCreateTestClientForHeaders always uses _config, which can undermine tests that set up a different ClientConfiguration (e.g., default headers overrides). Make the helper accept an optional config.
- private (OpenFgaClient client, Mock<HttpMessageHandler> handler) CreateTestClientForHeaders<TResponse>( - TResponse response, - Func<HttpRequestMessage, bool>? requestValidator = null) { + private (OpenFgaClient client, Mock<HttpMessageHandler> handler) CreateTestClientForHeaders<TResponse>( + TResponse response, + Func<HttpRequestMessage, bool>? requestValidator = null, + ClientConfiguration? config = null) { var mockHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict); ... - var httpClient = new HttpClient(mockHandler.Object); - return (new OpenFgaClient(_config, httpClient), mockHandler); + var httpClient = new HttpClient(mockHandler.Object); + return (new OpenFgaClient(config ?? _config, httpClient), mockHandler); }
2575-2606: This test doesn’t actually exercise default override; pass the configured defaultsYou build configWithDefaults but CreateTestClientForHeaders uses _config. After the helper change, pass configWithDefaults to ensure you’re testing per-request overriding defaults.
- var (client, mockHandler) = CreateTestClientForHeaders(expectedResponse, req => + var (client, mockHandler) = CreateTestClientForHeaders(expectedResponse, req => req.Headers.Contains(TestHeaders.RequestId) && req.Headers.GetValues(TestHeaders.RequestId).First() == "override-request-id" - ); + , configWithDefaults);
2491-2524: Add coverage: reserved header validation on non-Check endpointsYou exercise reserved headers via Check(). Consider adding a similar assertion for CreateStore/Read/List paths to catch regressions if any call-site skips validation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs(5 hunks)src/OpenFga.Sdk/Api/OpenFgaApi.cs(31 hunks)src/OpenFga.Sdk/ApiClient/ApiClient.cs(3 hunks)src/OpenFga.Sdk/Client/Client.cs(18 hunks)src/OpenFga.Sdk/Client/ClientConfiguration.cs(4 hunks)src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientCreateStoreOptions.cs(1 hunks)src/OpenFga.Sdk/Client/Model/ClientExpandOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientListObjectsOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientListStoresOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientListUsersOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientRequestOptions.cs(1 hunks)src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs(2 hunks)src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (21)
src/OpenFga.Sdk/Client/Model/ClientCreateStoreOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientListUsersOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientListObjectsOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/Client/ClientConfiguration.cs (4)
ClientConfiguration(31-152)ClientConfiguration(36-45)ClientConfiguration(50-50)EnsureValid(75-89)
src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientRequestOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientExpandOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/ClientConfiguration.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/ApiClient/ApiClient.cs (2)
src/OpenFga.Sdk/Api/OpenFgaApi.cs (13)
Task(52-74)Task(85-107)Task(117-133)Task(143-164)Task(175-197)Task(207-228)Task(239-261)Task(273-297)Task(308-330)Task(341-363)Task(374-398)Task(409-433)Task(445-472)src/OpenFga.Sdk/ApiClient/OAuth2Client.cs (3)
Task(135-162)Task(164-193)Task(200-209)
src/OpenFga.Sdk/Client/Model/ClientListStoresOptions.cs (2)
src/OpenFga.Sdk/Client/Client.cs (1)
IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
src/OpenFga.Sdk/Client/Client.cs (4)
src/OpenFga.Sdk/ApiClient/ApiClient.cs (3)
ApiClient(30-209)ApiClient(41-67)IDictionary(186-206)src/OpenFga.Sdk/Client/ClientConfiguration.cs (4)
ClientConfiguration(31-152)ClientConfiguration(36-45)ClientConfiguration(50-50)ValidateHeaders(121-151)src/OpenFga.Sdk/Api/OpenFgaApi.cs (16)
Task(52-74)Task(85-107)Task(117-133)Task(143-164)Task(175-197)Task(207-228)Task(239-261)Task(273-297)Task(308-330)Task(341-363)Task(374-398)Task(409-433)Task(445-472)Task(486-520)Task(531-553)Task(565-590)src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs (1)
ClientWriteOptions(59-73)
src/OpenFga.Sdk/Api/OpenFgaApi.cs (2)
src/OpenFga.Sdk/Client/Client.cs (17)
Task(81-114)Task(116-139)Task(141-182)Task(184-215)Task(246-248)Task(253-256)Task(261-262)Task(267-268)Task(277-280)Task(285-288)Task(293-302)Task(307-318)Task(327-330)Task(335-349)Task(354-412)Task(417-419)IDictionary(74-78)src/OpenFga.Sdk/ApiClient/ApiClient.cs (1)
IDictionary(186-206)
🔇 Additional comments (18)
src/OpenFga.Sdk/Client/Model/ClientReadChangesOptions.cs (1)
14-15: LGTM! Headers property correctly added for per-request header support.The implementation follows the expected pattern: proper using statement and nullable IDictionary property. The
/// <inheritdoc />comment suggests the property is defined in a parent interface.Note: The file is marked as auto-generated. Verify that future code generation won't overwrite these manual additions, or update the generation template to include Headers.
Also applies to: 35-36
src/OpenFga.Sdk/Client/Model/ClientCheckOptions.cs (1)
15-15: LGTM! Headers property correctly added.The implementation is consistent with the per-request headers feature. Type and nullability are appropriate for HTTP header dictionaries.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientReadAssertionsOptions.cs (1)
14-15: LGTM! Headers property correctly added.The implementation follows the established pattern for per-request header support across option models.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientBatchCheckOptions.cs (1)
15-15: LGTM! Headers property correctly added.Consistent implementation enabling per-request headers for batch check operations.
Also applies to: 41-42
src/OpenFga.Sdk/Client/Model/ClientListRelationsOptions.cs (1)
15-15: LGTM! Headers property correctly added.The implementation properly extends ClientListRelationsOptions with per-request header support.
Also applies to: 37-38
src/OpenFga.Sdk/Client/Model/ClientExpandOptions.cs (1)
15-15: LGTM! Headers property correctly added.Consistent with the broader per-request headers implementation across all option models.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientListObjectsOptions.cs (1)
15-15: LGTM! Headers property correctly added.The implementation properly enables per-request header customization for list objects operations.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientListUsersOptions.cs (1)
15-15: LGTM! Headers property correctly added.Final option model correctly extended with per-request headers support, completing the consistent implementation across all client option classes.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelOptions.cs (2)
10-10: Verify auto-generated file maintenance approach.The comment states this file is auto-generated and should not be edited, yet this PR manually adds the
Headersproperty. Ensure that either:
- The code generator has been updated to include these changes, or
- The comment is outdated and should be removed/updated
Otherwise, manual changes may be lost on the next code generation.
14-14: LGTM! Consistent implementation of per-request headers.The addition of the
Headersproperty with the appropriate using directive follows the established pattern for per-request header support across the SDK.Note: The filename has a typo ("Authorizaion" vs "Authorization"), though this is a pre-existing issue not introduced by this PR.
Also applies to: 32-33
src/OpenFga.Sdk/Client/Model/ClientReadAuthorizaionModelsOptions.cs (1)
14-14: LGTM! Consistent implementation.The
Headersproperty addition follows the same pattern as other option classes, enabling per-request header customization for read authorization models operations.Note: The filename contains the same "Authorizaion" typo, which is a pre-existing issue.
Also applies to: 35-36
src/OpenFga.Sdk/Client/Model/ClientWriteAssertionsOptions.cs (1)
14-14: LGTM! Consistent implementation.The
Headersproperty addition aligns with the per-request header support pattern implemented across all client option classes.Also applies to: 33-34
src/OpenFga.Sdk/Client/Model/ClientWriteOptions.cs (1)
14-14: LGTM! Consistent implementation.The
Headersproperty is correctly added toClientWriteOptions, maintaining consistency with other option classes while preserving existing properties likeTransaction.Also applies to: 71-72
src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs (1)
15-15: LGTM! Consistent implementation.The
Headersproperty is appropriately added toClientReadOptions, following the standard pattern for per-request header support.Also applies to: 39-40
src/OpenFga.Sdk/Client/Model/ClientRequestOptions.cs (1)
14-14: LGTM! Well-documented interface extension.The
Headersproperty addition to the baseClientRequestOptionsinterface is well-documented, clearly explaining the merge behavior and precedence rules. The documentation aligns with theBuildHeadersimplementation inApiClientwhere per-request headers override defaults when keys collide.Also applies to: 22-27
src/OpenFga.Sdk/Client/Model/ClientCreateStoreOptions.cs (1)
14-14: LGTM! Consistent implementation.The
Headersproperty is correctly added toClientCreateStoreOptions. The explicit inheritance fromClientRequestOptionsin the interface (line 18) makes the contract clear.Also applies to: 20-23
src/OpenFga.Sdk/Client/Model/ClientListStoresOptions.cs (1)
14-14: LGTM! Consistent implementation.The
Headersproperty addition completes the per-request header support pattern across the SDK's option classes. The implementation is consistent with all other option models.Also applies to: 36-37
src/OpenFga.Sdk/Client/Client.cs (1)
68-78: Good centralization of per-request header handlingExtractHeaders centralizes validation and avoids duplication. This is the right place to enforce safety before wiring to OpenFgaApi.
rhamzeh
left a comment
There was a problem hiding this comment.
Also please add the documentation to the README and Changelog - breaking changes should be clearly documented in the changelog in the PR that makes them
There was a problem hiding this comment.
Pull Request Overview
Introduce per-request custom HTTP headers to the .NET SDK, with validation and consistent propagation through the high-level client and low-level API.
- Add IRequestOptions and IClientRequestOptions with Headers dictionaries; implement Headers across all client option classes.
- Enforce header validation (reserved headers, CR/LF injection, null/whitespace keys) and merge default, OAuth, and per-request headers with clear precedence.
- Update OpenFgaApi and Client to accept and forward options; add documentation and comprehensive tests.
Reviewed Changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/OpenFga.Sdk/Model/RequestOptions.cs | Introduces IRequestOptions and RequestOptions holding per-request Headers. |
| src/OpenFga.Sdk/Configuration/Configuration.cs | Adds ReservedHeaders and ValidateHeaders; validates DefaultHeaders in EnsureValid. |
| src/OpenFga.Sdk/Client/Model/ClientRequestOptions.cs | Adds IClientRequestOptions and concrete ClientRequestOptions with Headers property. |
| src/OpenFga.Sdk/Client/Model/ClientRequestOptsWithStoreId.cs | Updates interface inheritance to use IClientRequestOptions. |
| src/OpenFga.Sdk/Client/Model/Client*.cs (multiple) | Adds Headers property to all client option classes (check, write, read, expand, list, etc.). |
| src/OpenFga.Sdk/Client/Client.cs | Propagates options to API layer and merges per-request headers in specific flows. |
| src/OpenFga.Sdk/ApiClient/ApiClient.cs | Extends SendRequestAsync to accept IRequestOptions; builds merged headers via BuildHeaders with validation and precedence. |
| src/OpenFga.Sdk/Api/OpenFgaApi.cs | Adds IRequestOptions? options parameter to all methods and forwards to ApiClient. |
| src/OpenFga.Sdk/Client/ClientConfiguration.cs | Adds missing usings needed for DefaultHeaders usage. |
| src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs | Adds extensive tests for header validation, precedence, overrides, and concurrency. |
| README.md | Documents default and per-request header usage with examples. |
| CHANGELOG.md | Notes new feature and breaking API signature changes; explains renaming and usage. |
| .openapi-generator/FILES | Tracks new RequestOptions.cs in generated file list. |
Comments suppressed due to low confidence (1)
CHANGELOG.md:1
- Corrected spelling of 'overiding' to 'overriding'.
# Changelog
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Description
This pull request introduces comprehensive support for custom HTTP headers in the .NET SDK, including both default headers for all requests and per-request header overrides.
Per-Request Headers
Headersproperty to all client options classes (e.g.,ClientCheckOptions,ClientWriteOptions, etc.) via the newIClientRequestOptionsinterfaceInterface-Based Architecture
IRequestOptionsinterface andRequestOptionsclass inModelnamespaceIClientRequestOptionsinterface andClientRequestOptionsclass inClient.ModelnamespaceIClientRequestOptionsHeader Validation
ValidateHeaders()method inClientConfigurationto prevent:Enhanced DefaultHeaders
DefaultHeadersinClientConfigurationnow includes validation viaEnsureValid()Breaking Changes
1. OpenFgaApi Methods
All 17 API methods now accept
IRequestOptions? optionsparameter instead ofIDictionary<string, string>? headers:Before:
After:
2. ClientRequestOptions Renamed
The base interface was renamed from
ClientRequestOptionstoIClientRequestOptionsto follow .NET naming conventions:Before:
After:
Note: If you're using the high-level
OpenFgaClient, no changes are required. The new functionality is additive via existingoptionsparameters.Usage Examples
Default Headers for All Requests
Per-Request Headers
Header Merge Behavior
When both default and per-request headers are provided:
References
Closes #116
Generated from → openfga/sdk-generator#640
Review Checklist
mainSummary by CodeRabbit