Skip to content

feat: per-request custom headers#133

Merged
evansims merged 12 commits intomainfrom
feat/per-request-custom-headers
Oct 21, 2025
Merged

feat: per-request custom headers#133
evansims merged 12 commits intomainfrom
feat/per-request-custom-headers

Conversation

@evansims
Copy link
Contributor

@evansims evansims commented Oct 14, 2025

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

  • Added Headers property to all client options classes (e.g., ClientCheckOptions, ClientWriteOptions, etc.) via the new IClientRequestOptions interface
  • Per-request headers override default headers when both define the same key
  • Headers are validated to prevent reserved headers and injection attacks

Interface-Based Architecture

  • API Level: Added IRequestOptions interface and RequestOptions class in Model namespace
  • Client Level: Added IClientRequestOptions interface and ClientRequestOptions class in Client.Model namespace
  • All existing client options interfaces now inherit from IClientRequestOptions

Header Validation

  • Added ValidateHeaders() method in ClientConfiguration to prevent:
    • Reserved HTTP headers (Authorization, Content-Type, Host, etc.)
    • Header injection attacks (CR/LF characters)
    • Null or whitespace header names
    • Null header values

Enhanced DefaultHeaders

  • DefaultHeaders in ClientConfiguration now includes validation via EnsureValid()
  • Works seamlessly with per-request headers (merge with override behavior)

Breaking Changes

1. OpenFgaApi Methods

All 17 API methods now accept IRequestOptions? options parameter instead of IDictionary<string, string>? headers:

Before:

await api.Check(storeId, body, cancellationToken);

After:

var options = new RequestOptions {
    Headers = new Dictionary<string, string> { { "X-Custom-Header", "value" } }
};
await api.Check(storeId, body, options, cancellationToken);

2. ClientRequestOptions Renamed

The base interface was renamed from ClientRequestOptions to IClientRequestOptions to follow .NET naming conventions:

Before:

var options = obj as ClientRequestOptions;

After:

var options = obj as IClientRequestOptions;

Note: If you're using the high-level OpenFgaClient, no changes are required. The new functionality is additive via existing options parameters.

Usage Examples

Default Headers for All Requests

var configuration = new ClientConfiguration() {
    ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL") ?? "http://localhost:8080",
    StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
    AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"),
    DefaultHeaders = new Dictionary<string, string> {
        { "X-Custom-Header", "default-value" },
        { "X-Request-Source", "my-app" }
    }
};
var fgaClient = new OpenFgaClient(configuration);

Per-Request Headers

var body = new ClientCheckRequest {
    User = "user:anne",
    Relation = "viewer",
    Object = "document:roadmap"
};

var options = new ClientCheckOptions {
    Headers = new Dictionary<string, string> {
        { "X-Request-ID", "123e4567-e89b-12d3-a456-426614174000" },
        { "X-Custom-Header", "custom-value" } // Overrides default header
    }
};

var response = await fgaClient.Check(body, options);

Header Merge Behavior

When both default and per-request headers are provided:

  • Per-request headers take precedence for duplicate keys
  • All headers are validated against the reserved headers list
  • Final headers are the union of both, with per-request overrides

References

Closes #116

Generated from → openfga/sdk-generator#640

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

  • New Features
    • Added per-request custom HTTP headers across all client operations (check, read/write, expand, list, stores, models, changes).
    • Headers merge with client defaults; per-request values take precedence.
    • Validation prevents reserved/invalid headers to ensure safe requests.
  • Documentation
    • Updated API and options docs to describe header usage and precedence.
  • Tests
    • Extensive new tests covering header validation, precedence, overrides, and concurrency to improve reliability.

@evansims evansims added the enhancement New feature or request label Oct 14, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 14, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Adds 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

Cohort / File(s) Summary of Changes
Public API methods accept per-request headers
src/OpenFga.Sdk/Api/OpenFgaApi.cs
Adds optional IDictionary<string, string>? headers to all public API methods and forwards to ApiClient; updates XML docs.
ApiClient header merge and forwarding
src/OpenFga.Sdk/ApiClient/ApiClient.cs
Adds perRequestHeaders parameter to SendRequestAsync overloads; introduces BuildHeaders to merge OAuth token and per-request headers; forwards final headers to HTTP layer.
Client passes headers from options
src/OpenFga.Sdk/Client/Client.cs
Adds ExtractHeaders(options) to validate and extract headers from ClientRequestOptions; propagates headers to API calls.
Header validation and reserved set
src/OpenFga.Sdk/Client/ClientConfiguration.cs
Adds ValidateHeaders(...) and a ReservedHeaders set; validates default and per-request headers (non-empty names, non-null values, no CR/LF, blocks reserved headers).
Request option models gain Headers
src/OpenFga.Sdk/Client/Model/*Options.cs (ClientRequestOptions.cs, ClientCheckOptions.cs, ClientBatchCheckOptions.cs, ClientCreateStoreOptions.cs, ClientExpandOptions.cs, ClientListObjectsOptions.cs, ClientListRelationsOptions.cs, ClientListStoresOptions.cs, ClientListUsersOptions.cs, ClientReadOptions.cs, ClientReadChangesOptions.cs, ClientReadAssertionsOptions.cs, ClientReadAuthorizationModelOptions.cs, ClientReadAuthorizationModelsOptions.cs, ClientWriteOptions.cs, ClientWriteAssertionsOptions.cs)
Adds public IDictionary<string, string>? Headers { get; set; } to option classes and interface to carry per-request headers.
Tests for headers behavior
src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs
Adds helper constants and methods for header testing; extensive tests for reserved headers, overrides, errors, per-operation inclusion, and concurrency isolation.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The implementation adds an optional headers parameter across all relevant API client methods, centralizes default headers in ClientConfiguration with validation, extends all request option models, updates the ApiClient and Client logic to merge headers correctly, and includes comprehensive tests covering header behavior. These changes collectively fulfill the objectives of issue #116 by providing a first-class mechanism for per-request HTTP headers and enabling contextual metadata propagation as specified.
Out of Scope Changes Check ✅ Passed All modifications are focused on introducing per-request custom header support, including API signature updates, header validation logic, option model extensions, client implementation adjustments, and associated tests. There are no unrelated feature additions or modifications outside the scope of issue #116’s goal of per-request HTTP header support.
Docstring Coverage ✅ Passed Docstring coverage is 87.36% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: per-request custom headers" directly and clearly summarizes the primary change in the changeset. The PR's core objective is to add support for per-request custom HTTP headers to the .NET OpenFGA SDK, and the title accurately captures this intent. The title is specific and descriptive—it conveys meaningful information about the feature being added without using vague terms like "misc updates" or generic placeholders. While the changeset includes additional related work such as header validation, default headers support, and override behavior, the title appropriately focuses on the main user-facing feature without needing to cover every implementation detail, which is acceptable per the evaluation criteria.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

evansims and others added 3 commits October 14, 2025 11:48
…tainsKey

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@evansims evansims marked this pull request as ready for review October 14, 2025 20:01
@evansims evansims requested a review from a team as a code owner October 14, 2025 20:01
@evansims
Copy link
Contributor Author

I will have a follow-up PR with documentation coverage for this feature.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 hardening

The 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 config

CreateTestClientForHeaders 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 defaults

You 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 endpoints

You 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

📥 Commits

Reviewing files that changed from the base of the PR and between a040c45 and 00b4c60.

📒 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 Headers property. 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 Headers property 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 Headers property 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 Headers property 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 Headers property is correctly added to ClientWriteOptions, maintaining consistency with other option classes while preserving existing properties like Transaction.

Also applies to: 71-72

src/OpenFga.Sdk/Client/Model/ClientReadOptions.cs (1)

15-15: LGTM! Consistent implementation.

The Headers property is appropriately added to ClientReadOptions, 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 Headers property addition to the base ClientRequestOptions interface is well-documented, clearly explaining the merge behavior and precedence rules. The documentation aligns with the BuildHeaders implementation in ApiClient where 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 Headers property is correctly added to ClientCreateStoreOptions. The explicit inheritance from ClientRequestOptions in 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 Headers property 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 handling

ExtractHeaders centralizes validation and avoids duplication. This is the right place to enforce safety before wiring to OpenFgaApi.

Copy link
Member

@rhamzeh rhamzeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@evansims evansims requested a review from rhamzeh October 16, 2025 20:20
@evansims evansims requested review from a team as code owners October 16, 2025 20:47
@evansims evansims requested review from Copilot and rhamzeh October 17, 2025 03:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@evansims evansims changed the title feat(DXAZD-1900): per-request custom headers feat: per-request custom headers Oct 17, 2025
@evansims evansims added this pull request to the merge queue Oct 21, 2025
Merged via the queue into main with commit e5c46f5 Oct 21, 2025
23 checks passed
@evansims evansims deleted the feat/per-request-custom-headers branch October 21, 2025 15:10
@coderabbitai coderabbitai bot mentioned this pull request Oct 21, 2025
4 tasks
@coderabbitai coderabbitai bot mentioned this pull request Feb 4, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add support for per-request custom HTTP headers in SDK API calls

4 participants

Comments