From 74e8de97b7ed9072488930f1bfafa8352db275ba Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Sat, 13 Sep 2025 09:09:40 -0400 Subject: [PATCH 1/5] feat: allow overriding headers per request --- config/clients/go/CHANGELOG.md.mustache | 1 + config/clients/go/config.overrides.json | 6 + .../go/template/README_initializing.mustache | 40 + config/clients/go/template/api.mustache | 19 + .../clients/go/template/api_client.mustache | 4 +- .../clients/go/template/api_headers_test.go | 838 ++++++++++++++++ .../go/template/client/client.mustache | 241 ++++- .../go/template/client/client_headers_test.go | 892 ++++++++++++++++++ .../go/template/example/example1/example1.go | 18 + 9 files changed, 2020 insertions(+), 39 deletions(-) create mode 100644 config/clients/go/template/api_headers_test.go create mode 100644 config/clients/go/template/client/client_headers_test.go diff --git a/config/clients/go/CHANGELOG.md.mustache b/config/clients/go/CHANGELOG.md.mustache index 530eae9a2..4783d8a42 100644 --- a/config/clients/go/CHANGELOG.md.mustache +++ b/config/clients/go/CHANGELOG.md.mustache @@ -2,6 +2,7 @@ ## [Unreleased](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v{{packageVersion}}...HEAD) +- feat: add support for custom headers per request - feat: add contextual tuples support in Expand requests ## v0.7.1 diff --git a/config/clients/go/config.overrides.json b/config/clients/go/config.overrides.json index ace5538a3..cdd3f4c0d 100644 --- a/config/clients/go/config.overrides.json +++ b/config/clients/go/config.overrides.json @@ -45,6 +45,12 @@ "destinationFilename": "client/errors.go", "templateType": "SupportingFiles" }, + "client/client_headers_test.go": { + "destinationFilename": "client/client_headers_test.go" + }, + "api_headers_test.go": { + "destinationFilename": "api_headers_test.go" + }, "api_client_test.mustache": { "destinationFilename": "api_client_test.go", "templateType": "SupportingFiles" diff --git a/config/clients/go/template/README_initializing.mustache b/config/clients/go/template/README_initializing.mustache index fe510d26d..8c468f185 100644 --- a/config/clients/go/template/README_initializing.mustache +++ b/config/clients/go/template/README_initializing.mustache @@ -114,3 +114,43 @@ func main() { } } ``` + +### Custom Headers + +#### Default Headers +You can set default headers that will be sent with every request during client initialization: + +```golang +fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ + ApiUrl: os.Getenv("FGA_API_URL"), + StoreId: os.Getenv("FGA_STORE_ID"), + AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), + DefaultHeaders: map[string]string{ + "X-Custom-Header": "default-value", + "X-Request-Source": "my-app", + }, +}) +``` + +#### Per-Request Headers + +You can also send custom headers on a per-request basis by using the `Options` parameter. Custom headers will override any default headers set in the client configuration. + +```golang +// Add custom headers to a specific request +checkResponse, err := fgaClient.Check(context.Background()). + Body(client.ClientCheckRequest{ + User: "user:anne", + Relation: "viewer", + Object: "document:roadmap", + }). + Options(client.ClientCheckOptions{ + RequestOptions: client.RequestOptions{ + Headers: map[string]string{ + "X-Request-ID": "123e4567-e89b-12d3-a456-426614174000", + "X-Custom-Header": "custom-value", // these override any default headers set + }, + }, + }). + Execute() +``` diff --git a/config/clients/go/template/api.mustache b/config/clients/go/template/api.mustache index 8ee3855d4..e12ef404f 100644 --- a/config/clients/go/template/api.mustache +++ b/config/clients/go/template/api.mustache @@ -24,6 +24,12 @@ var ( ) {{#generateInterfaces}} +type RequestOptions struct { + MaxRetry *int `json:"max_retry,omitempty"` + MinWaitInMs *int `json:"min_wait_in_ms,omitempty"` + Headers map[string]string `json:"headers,omitempty"` +} + type {{classname}} interface { {{#operation}} @@ -61,13 +67,20 @@ type {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request s {{#allParams}} {{paramName}} {{^isPathParam}}*{{/isPathParam}}{{{dataType}}} {{/allParams}} + options RequestOptions } + {{#allParams}}{{^isPathParam}} func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request) {{vendorExtensions.x-export-param-name}}({{paramName}} {{{dataType}}}) {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request { r.{{paramName}} = &{{paramName}} return r }{{/isPathParam}}{{/allParams}} +func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request) Options(options RequestOptions) {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request { + r.options = options + return r +} + func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request) Execute() ({{#returnType}}{{{.}}}, {{/returnType}}*http.Response, error) { return r.ApiService.{{nickname}}Execute(r) } @@ -281,6 +294,7 @@ func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&class // body params requestBody = r.{{paramName}} {{/bodyParams}} + {{#authMethods}} {{#isApiKey}} {{^isKeyInCookie}} @@ -318,6 +332,11 @@ func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&class {{/isApiKey}} {{/authMethods}} + // if any override headers were in the options, set them now + for header, val := range r.options.Headers { + localVarHeaderParams[header] = val + } + retryParams := a.client.cfg.RetryParams for i := 0; i < retryParams.MaxRetry+1; i++ { req, err := a.client.prepareRequest(r.ctx, path, httpMethod, requestBody, localVarHeaderParams, localVarQueryParams) diff --git a/config/clients/go/template/api_client.mustache b/config/clients/go/template/api_client.mustache index eb02fa47c..c5fd0986f 100644 --- a/config/clients/go/template/api_client.mustache +++ b/config/clients/go/template/api_client.mustache @@ -290,7 +290,9 @@ func (c *APIClient) prepareRequest( localVarRequest.Header.Set("User-Agent", c.cfg.UserAgent) for header, value := range c.cfg.DefaultHeaders { - localVarRequest.Header.Set(header, value) + if localVarRequest.Header.Get(header) == "" { + localVarRequest.Header.Set(header, value) + } } if ctx != nil { diff --git a/config/clients/go/template/api_headers_test.go b/config/clients/go/template/api_headers_test.go new file mode 100644 index 000000000..5cc990730 --- /dev/null +++ b/config/clients/go/template/api_headers_test.go @@ -0,0 +1,838 @@ +package openfga_test + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + + openfga "github.com/openfga/go-sdk" +) + +// Test helpers and setup + +// Constants to avoid duplication +const ( + apiDefaultHeaderName = "Default-Header" + apiDefaultHeaderValue = "default-value" + apiOverriddenValue = "overridden-value" + apiCustomHeaderName = "X-Custom-Header" + apiCustomHeaderValue = "custom-value" + apiTestUser = "user:anne" + apiTestRelation = "viewer" + apiTestObject = "document:roadmap" + apiTestStoreId = "01H0H015178Y2V4CX10C2KGHF4" + apiRequestFailedMsg = "API request failed: %v" + apiExpectedCustomMsg = "Expected X-Custom-Header to be 'custom-value', got '%s'" + apiExpectedOverriddenMsg = "Expected Default-Header to be overridden to 'overridden-value', got '%s'" + apiExpectedDefaultMsg = "Expected Default-Header to be 'default-value', got '%s'" +) + +// createAPITestServer creates a test server that captures headers and returns appropriate responses +func createAPITestServer(t *testing.T, capturedHeaders *map[string]string, responseBody string) *httptest.Server { + t.Helper() + + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + *capturedHeaders = make(map[string]string) + for name, values := range r.Header { + if len(values) > 0 { + (*capturedHeaders)[name] = values[0] + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(responseBody)) + })) +} + +// createAPITestClient creates a test API client with the given server URL and default headers +func createAPITestClient(t *testing.T, serverURL string, defaultHeaders map[string]string) *openfga.APIClient { + t.Helper() + + config, err := openfga.NewConfiguration(openfga.Configuration{ + ApiUrl: serverURL, + DefaultHeaders: defaultHeaders, + }) + if err != nil { + t.Fatalf("Failed to create API configuration: %v", err) + } + + return openfga.NewAPIClient(config) +} + +// Misc tests + +// Test RequestOptions structure directly at API level +func TestAPIRequestOptionsStructure(t *testing.T) { + t.Run("RequestOptionsWithAllFields", func(t *testing.T) { + options := openfga.RequestOptions{ + Headers: map[string]string{ + "Test-Header": "test-value", + }, + MaxRetry: openfga.PtrInt(3), + MinWaitInMs: openfga.PtrInt(1000), + } + + if options.Headers["Test-Header"] != "test-value" { + t.Errorf("Expected Test-Header to be 'test-value', got '%s'", options.Headers["Test-Header"]) + } + + if options.MaxRetry == nil || *options.MaxRetry != 3 { + t.Errorf("Expected MaxRetry to be 3, got %v", options.MaxRetry) + } + + if options.MinWaitInMs == nil || *options.MinWaitInMs != 1000 { + t.Errorf("Expected MinWaitInMs to be 1000, got %v", options.MinWaitInMs) + } + }) + + t.Run("RequestOptionsWithNilHeaders", func(t *testing.T) { + options := openfga.RequestOptions{ + Headers: nil, + MaxRetry: openfga.PtrInt(3), + MinWaitInMs: openfga.PtrInt(1000), + } + + if options.Headers != nil { + t.Errorf("Expected Headers to be nil, got %v", options.Headers) + } + }) + + t.Run("RequestOptionsWithEmptyHeaders", func(t *testing.T) { + options := openfga.RequestOptions{ + Headers: map[string]string{}, + MaxRetry: openfga.PtrInt(3), + MinWaitInMs: openfga.PtrInt(1000), + } + + if len(options.Headers) != 0 { + t.Errorf("Expected Headers to be empty, got %v", options.Headers) + } + }) +} + +// Test header precedence and merging behavior +func TestAPIHeaderPrecedenceHandling(t *testing.T) { + t.Run("CustomHeadersOverrideDefaults", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + "Header-1": "default-1", + "Header-2": "default-2", + "Header-3": "default-3", + }) + + _, _, err := client.OpenFgaApi.Check(context.Background(), apiTestStoreId). + Body(openfga.CheckRequest{ + TupleKey: openfga.CheckRequestTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + "Header-1": "overridden-1", // Override the default + "Header-4": "custom-4", + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders["Header-1"] != "overridden-1" { + t.Errorf("Expected Header-1 to be 'overridden-1', got '%s'", capturedHeaders["Header-1"]) + } + + if capturedHeaders["Header-2"] != "default-2" { + t.Errorf("Expected Header-2 to be 'default-2', got '%s'", capturedHeaders["Header-2"]) + } + + if capturedHeaders["Header-3"] != "default-3" { + t.Errorf("Expected Header-3 to be 'default-3', got '%s'", capturedHeaders["Header-3"]) + } + + if capturedHeaders["Header-4"] != "custom-4" { + t.Errorf("Expected Header-4 to be 'custom-4', got '%s'", capturedHeaders["Header-4"]) + } + }) +} + +// Test the header handling for the methods + +func TestCheckAPIMethodHeaderHandling(t *testing.T) { + t.Run("CheckAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.Check(context.Background(), apiTestStoreId). + Body(openfga.CheckRequest{ + TupleKey: openfga.CheckRequestTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) + + t.Run("CheckAPIWithoutCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.Check(context.Background(), apiTestStoreId). + Body(openfga.CheckRequest{ + TupleKey: openfga.CheckRequestTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiDefaultHeaderName] != apiDefaultHeaderValue { + t.Errorf(apiExpectedDefaultMsg, capturedHeaders[apiDefaultHeaderName]) + } + + if _, exists := capturedHeaders[apiCustomHeaderName]; exists { + t.Error("Did not expect X-Custom-Header to be present") + } + }) + + t.Run("CheckAPIWithEmptyHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, nil) + + _, _, err := client.OpenFgaApi.Check(context.Background(), apiTestStoreId). + Body(openfga.CheckRequest{ + TupleKey: openfga.CheckRequestTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{}, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + for header := range capturedHeaders { + if strings.HasPrefix(header, "X-") || header == apiDefaultHeaderName { + t.Errorf("Unexpected custom header found: %s", header) + } + } + }) +} + +func TestBatchCheckAPIMethodHeaderHandling(t *testing.T) { + t.Run("BatchCheckAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"test-correlation-id": {"allowed": true}}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.BatchCheck(context.Background(), apiTestStoreId). + Body(openfga.BatchCheckRequest{ + Checks: []openfga.BatchCheckItem{ + { + TupleKey: openfga.CheckRequestTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + CorrelationId: "test-correlation-id", + }, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestWriteAPIMethodHeaderHandling(t *testing.T) { + t.Run("WriteAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.Write(context.Background(), apiTestStoreId). + Body(openfga.WriteRequest{ + Writes: &openfga.WriteRequestWrites{ + TupleKeys: []openfga.TupleKey{ + { + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + }, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestReadAPIMethodHeaderHandling(t *testing.T) { + t.Run("ReadAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"tuples": []}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.Read(context.Background(), apiTestStoreId). + Body(openfga.ReadRequest{ + TupleKey: &openfga.ReadRequestTupleKey{ + User: openfga.PtrString(apiTestUser), + Relation: openfga.PtrString(apiTestRelation), + Object: openfga.PtrString(apiTestObject), + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestExpandAPIMethodHeaderHandling(t *testing.T) { + t.Run("ExpandAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"tree": {"root": {"name": "document:roadmap#viewer"}}}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.Expand(context.Background(), apiTestStoreId). + Body(openfga.ExpandRequest{ + TupleKey: openfga.ExpandRequestTupleKey{ + Relation: apiTestRelation, + Object: apiTestObject, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestListObjectsAPIMethodHeaderHandling(t *testing.T) { + t.Run("ListObjectsAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"objects": ["document:roadmap"]}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ListObjects(context.Background(), apiTestStoreId). + Body(openfga.ListObjectsRequest{ + User: apiTestUser, + Relation: apiTestRelation, + Type: "document", + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestListUsersAPIMethodHeaderHandling(t *testing.T) { + t.Run("ListUsersAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"users": [{"object": {"type": "user", "id": "anne"}}]}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ListUsers(context.Background(), apiTestStoreId). + Body(openfga.ListUsersRequest{ + Object: openfga.FgaObject{ + Type: "document", + Id: "roadmap", + }, + Relation: apiTestRelation, + UserFilters: []openfga.UserTypeFilter{ + {Type: "user"}, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestStoreAPIMethodHeaderHandling(t *testing.T) { + t.Run("ListStoresAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"stores": [{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}]}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ListStores(context.Background()). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) + + t.Run("CreateStoreAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.CreateStore(context.Background()). + Body(openfga.CreateStoreRequest{ + Name: "test", + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) + + t.Run("GetStoreAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.GetStore(context.Background(), apiTestStoreId). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) + + t.Run("DeleteStoreAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, err := client.OpenFgaApi.DeleteStore(context.Background(), apiTestStoreId). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestReadAuthorizationModelAPIMethodHeaderHandling(t *testing.T) { + t.Run("ReadAuthorizationModelAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"authorization_model": {"id": "01H0H015178Y2V4CX10C2KGHF4", "schema_version": "1.1"}}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ReadAuthorizationModel(context.Background(), apiTestStoreId, apiTestStoreId). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestWriteAuthorizationModelAPIMethodHeaderHandling(t *testing.T) { + t.Run("WriteAuthorizationModelAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"authorization_model_id": "01H0H015178Y2V4CX10C2KGHF4"}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.WriteAuthorizationModel(context.Background(), apiTestStoreId). + Body(openfga.WriteAuthorizationModelRequest{ + SchemaVersion: "1.1", + TypeDefinitions: []openfga.TypeDefinition{ + { + Type: "user", + }, + { + Type: "document", + Relations: &map[string]openfga.Userset{ + "viewer": {}, + }, + }, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestReadChangesAPIMethodHeaderHandling(t *testing.T) { + t.Run("ReadChangesAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"changes": [], "continuation_token": ""}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ReadChanges(context.Background(), apiTestStoreId). + Type_("document"). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} + +func TestAssertionsAPIMethodHeaderHandling(t *testing.T) { + t.Run("ReadAssertionsAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{"assertions": []}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, _, err := client.OpenFgaApi.ReadAssertions(context.Background(), apiTestStoreId, apiTestStoreId). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) + + t.Run("WriteAssertionsAPIWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createAPITestServer(t, &capturedHeaders, `{}`) + defer server.Close() + + client := createAPITestClient(t, server.URL, map[string]string{ + apiDefaultHeaderName: apiDefaultHeaderValue, + }) + + _, err := client.OpenFgaApi.WriteAssertions(context.Background(), apiTestStoreId, apiTestStoreId). + Body(openfga.WriteAssertionsRequest{ + Assertions: []openfga.Assertion{ + { + TupleKey: openfga.AssertionTupleKey{ + User: apiTestUser, + Relation: apiTestRelation, + Object: apiTestObject, + }, + Expectation: true, + }, + }, + }). + Options(openfga.RequestOptions{ + Headers: map[string]string{ + apiCustomHeaderName: apiCustomHeaderValue, + apiDefaultHeaderName: apiOverriddenValue, + }, + }). + Execute() + + if err != nil { + t.Fatalf(apiRequestFailedMsg, err) + } + + if capturedHeaders[apiCustomHeaderName] != apiCustomHeaderValue { + t.Errorf(apiExpectedCustomMsg, capturedHeaders[apiCustomHeaderName]) + } + + if capturedHeaders[apiDefaultHeaderName] != apiOverriddenValue { + t.Errorf(apiExpectedOverriddenMsg, capturedHeaders[apiDefaultHeaderName]) + } + }) +} diff --git a/config/clients/go/template/client/client.mustache b/config/clients/go/template/client/client.mustache index 6af4e5fbd..fb51e7614 100644 --- a/config/clients/go/template/client/client.mustache +++ b/config/clients/go/template/client/client.mustache @@ -107,21 +107,17 @@ func NewSdkClient(cfg *ClientConfiguration) (*{{appShortName}}Client, error) { }, nil } -type ClientRequestOptions struct { - MaxRetry *int `json:"max_retry,omitempty"` - MinWaitInMs *int `json:"min_wait_in_ms,omitempty"` -} +type RequestOptions = fgaSdk.RequestOptions type AuthorizationModelIdOptions struct { AuthorizationModelId *string `json:"authorization_model_id,omitempty"` } type ClientRequestOptionsWithAuthZModelId struct { - ClientRequestOptions + RequestOptions AuthorizationModelIdOptions } - type ClientTupleKey = fgaSdk.TupleKey type ClientTupleKeyWithoutCondition = fgaSdk.TupleKeyWithoutCondition type ClientCheckRequestTupleKey = fgaSdk.CheckRequestTupleKey @@ -146,6 +142,8 @@ type ClientBatchCheckRequest struct { // BatchCheckOptions represents options for server-side batch check operations type BatchCheckOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` MaxParallelRequests *int32 `json:"max_parallel_requests,omitempty"` @@ -571,6 +569,8 @@ type SdkClientListStoresRequestInterface interface { } type ClientListStoresOptions struct { + RequestOptions + PageSize *int32 `json:"page_size,omitempty"` ContinuationToken *string `json:"continuation_token,omitempty"` Name *string `json:"name,omitempty"` @@ -599,6 +599,7 @@ func (client *{{appShortName}}Client) ListStoresExecute(request SdkClientListSto req := client.{{appShortName}}Api.ListStores(request.GetContext()) options := request.GetOptions() if options != nil { + req = req.Options(options.RequestOptions) if options.PageSize != nil { req = req.PageSize(*options.PageSize) } @@ -609,6 +610,7 @@ func (client *{{appShortName}}Client) ListStoresExecute(request SdkClientListSto req = req.Name(*options.Name) } } + data, _, err := req.Execute() if err != nil { return nil, err @@ -647,6 +649,7 @@ type ClientCreateStoreRequest struct { } type ClientCreateStoreOptions struct { + RequestOptions } type ClientCreateStoreResponse = fgaSdk.CreateStoreResponse @@ -678,9 +681,20 @@ func (request *SdkClientCreateStoreRequest) GetBody() *ClientCreateStoreRequest{ } func (client *{{appShortName}}Client) CreateStoreExecute(request SdkClientCreateStoreRequestInterface) (*ClientCreateStoreResponse, error) { - data, _, err := client.{{appShortName}}Api.CreateStore(request.GetContext()).Body(fgaSdk.CreateStoreRequest{ + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + requestBody := fgaSdk.CreateStoreRequest{ Name: request.GetBody().Name, - }).Execute() + } + + data, _, err := client.{{appShortName}}Api. + CreateStore(request.GetContext()). + Body(requestBody). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -712,6 +726,8 @@ type SdkClientGetStoreRequestInterface interface{ } type ClientGetStoreOptions struct { + RequestOptions + StoreId *string `json:"store_id,omitempty"` } @@ -746,7 +762,16 @@ func (client *{{appShortName}}Client) GetStoreExecute(request SdkClientGetStoreR if err != nil { return nil, err } - data, _, err := client.{{appShortName}}Api.GetStore(request.GetContext(), *storeId).Execute() + + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + data, _, err := client.{{appShortName}}Api. + GetStore(request.GetContext(), *storeId). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -778,6 +803,8 @@ type SdkClientDeleteStoreRequestInterface interface{ } type ClientDeleteStoreOptions struct { + RequestOptions + StoreId *string `json:"store_id,omitempty"` } @@ -813,7 +840,16 @@ func (client *{{appShortName}}Client) DeleteStoreExecute(request SdkClientDelete if err != nil { return nil, err } - _, err = client.{{appShortName}}Api.DeleteStore(request.GetContext(), *storeId).Execute() + + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + _, err = client.{{appShortName}}Api. + DeleteStore(request.GetContext(), *storeId). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -847,6 +883,8 @@ type SdkClientReadAuthorizationModelsRequestInterface interface{ } type ClientReadAuthorizationModelsOptions struct { + RequestOptions + PageSize *int32 `json:"page_size,omitempty"` ContinuationToken *string `json:"continuation_token,omitempty"` StoreId *string `json:"store_id,omitempty"` @@ -890,7 +928,15 @@ func (client *{{appShortName}}Client) ReadAuthorizationModelsExecute(request Sdk return nil, err } - req := client.{{appShortName}}Api.ReadAuthorizationModels(request.GetContext(), *storeId) + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + req := client.{{appShortName}}Api. + ReadAuthorizationModels(request.GetContext(), *storeId). + Options(requestOptions) + pageSize := getPageSizeFromRequest(&pagingOpts) if pageSize != nil { req = req.PageSize(*pageSize) @@ -936,6 +982,8 @@ type SdkClientWriteAuthorizationModelRequestInterface interface { type ClientWriteAuthorizationModelRequest = fgaSdk.WriteAuthorizationModelRequest; type ClientWriteAuthorizationModelOptions struct { + RequestOptions + StoreId *string `json:"store_id,omitempty"` } @@ -979,7 +1027,17 @@ func (client *{{appShortName}}Client) WriteAuthorizationModelExecute(request Sdk if err != nil { return nil, err } - data, _, err := client.{{appShortName}}Api.WriteAuthorizationModel(request.GetContext(), *storeId).Body(*request.GetBody()).Execute() + + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + data, _, err := client.{{appShortName}}Api. + WriteAuthorizationModel(request.GetContext(), *storeId). + Body(*request.GetBody()). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -1018,6 +1076,8 @@ type ClientReadAuthorizationModelRequest struct { } type ClientReadAuthorizationModelOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` } @@ -1076,8 +1136,16 @@ func (client *{{appShortName}}Client) ReadAuthorizationModelExecute(request SdkC if err != nil { return nil, err } - data, _, err := client.{{appShortName}}Api.ReadAuthorizationModel(request.GetContext(), *storeId, *authorizationModelId).Execute() + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + data, _, err := client.{{appShortName}}Api. + ReadAuthorizationModel(request.GetContext(), *storeId, *authorizationModelId). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -1109,6 +1177,8 @@ type SdkClientReadLatestAuthorizationModelRequestInterface interface { } type ClientReadLatestAuthorizationModelOptions struct { + RequestOptions + StoreId *string `json:"store_id,omitempty"` } @@ -1149,6 +1219,7 @@ func (client *{{appShortName}}Client) ReadLatestAuthorizationModelExecute(reques } if request.GetOptions() != nil { opts.StoreId = request.GetOptions().StoreId + opts.RequestOptions = request.GetOptions().RequestOptions } req := client.ReadAuthorizationModels(request.GetContext()).Options(opts) @@ -1197,6 +1268,8 @@ type ClientReadChangesRequest struct { } type ClientReadChangesOptions struct { + RequestOptions + PageSize *int32 `json:"page_size,omitempty"` ContinuationToken *string `json:"continuation_token,omitempty"` StoreId *string `json:"store_id"` @@ -1246,7 +1319,9 @@ func (request *SdkClientReadChangesRequest) GetOptions() *ClientReadChangesOptio func (client *{{appShortName}}Client) ReadChangesExecute(request SdkClientReadChangesRequestInterface) (*ClientReadChangesResponse, error) { pagingOpts := ClientPaginationOptions{} + requestOptions := RequestOptions{} if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions pagingOpts.PageSize = request.GetOptions().PageSize pagingOpts.ContinuationToken = request.GetOptions().ContinuationToken } @@ -1256,7 +1331,9 @@ func (client *{{appShortName}}Client) ReadChangesExecute(request SdkClientReadCh return nil, err } - req := client.{{appShortName}}Api.ReadChanges(request.GetContext(), *storeId) + req := client.{{appShortName}}Api. + ReadChanges(request.GetContext(), *storeId). + Options(requestOptions) pageSize := getPageSizeFromRequest(&pagingOpts) if pageSize != nil { req = req.PageSize(*pageSize) @@ -1307,6 +1384,8 @@ type ClientReadRequest struct { } type ClientReadOptions struct { + RequestOptions + PageSize *int32 `json:"page_size,omitempty"` ContinuationToken *string `json:"continuation_token,omitempty"` StoreId *string `json:"store_id,omitempty"` @@ -1357,8 +1436,10 @@ func (request *SdkClientReadRequest) GetOptions() *ClientReadOptions { func (client *{{appShortName}}Client) ReadExecute(request SdkClientReadRequestInterface) (*ClientReadResponse, error) { pagingOpts := ClientPaginationOptions{} + requestOptions := RequestOptions{} var consistency *fgaSdk.ConsistencyPreference if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions pagingOpts.PageSize = request.GetOptions().PageSize pagingOpts.ContinuationToken = request.GetOptions().ContinuationToken consistency = request.GetOptions().Consistency @@ -1380,7 +1461,12 @@ func (client *{{appShortName}}Client) ReadExecute(request SdkClientReadRequestIn if err != nil { return nil, err } - data, _, err := client.{{appShortName}}Api.Read(request.GetContext(), *storeId).Body(body).Execute() + + data, _, err := client.{{appShortName}}Api. + Read(request.GetContext(), *storeId). + Body(body). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -1424,6 +1510,8 @@ type TransactionOptions struct { } type ClientWriteOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` Transaction *TransactionOptions `json:"transaction_options,omitempty"` @@ -1541,6 +1629,10 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest Writes: []ClientWriteRequestWriteResponse{}, Deletes: []ClientWriteRequestDeleteResponse{}, } + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } authorizationModelId, err := client.getAuthorizationModelId(request.GetAuthorizationModelIdOverride()) if err != nil { @@ -1572,7 +1664,12 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest } writeRequest.Deletes = &deletes } - _, httpResponse, err := client.{{appShortName}}Api.Write(request.GetContext(), *storeId).Body(writeRequest).Execute() + + _, httpResponse, err := client.{{appShortName}}Api. + Write(request.GetContext(), *storeId). + Body(writeRequest). + Options(requestOptions). + Execute() clientWriteStatus := SUCCESS if err != nil { @@ -1644,6 +1741,7 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest Writes: writeBody, }, options: &ClientWriteOptions{ + RequestOptions: options.RequestOptions, AuthorizationModelId: authorizationModelId, StoreId: request.GetStoreIdOverride(), }, @@ -1688,6 +1786,7 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest Deletes: deleteBody, }, options: &ClientWriteOptions{ + RequestOptions: options.RequestOptions, AuthorizationModelId: authorizationModelId, StoreId: request.GetStoreIdOverride(), }, @@ -1881,6 +1980,8 @@ type ClientCheckRequest struct { } type ClientCheckOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` @@ -1967,12 +2068,18 @@ func (client *{{appShortName}}Client) CheckExecute(request SdkClientCheckRequest ContextualTuples: fgaSdk.NewContextualTupleKeys(contextualTuples), AuthorizationModelId: authorizationModelId, } - + + requestOptions := RequestOptions{} if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions requestBody.Consistency = request.GetOptions().Consistency } - data, httpResponse, err := client.{{appShortName}}Api.Check(request.GetContext(), *storeId).Body(requestBody).Execute() + data, httpResponse, err := client.{{appShortName}}Api. + Check(request.GetContext(), *storeId). + Body(requestBody). + Options(requestOptions). + Execute() return &ClientCheckResponse{CheckResponse: data, HttpResponse: httpResponse}, err } @@ -2001,6 +2108,8 @@ type SdkClientBatchCheckClientRequestInterface interface { type ClientBatchCheckClientBody = []ClientCheckRequest type ClientBatchCheckClientOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` MaxParallelRequests *int32 `json:"max_parallel_requests,omitempty"` @@ -2064,12 +2173,15 @@ func (request *SdkClientBatchCheckClientRequest) GetOptions() *ClientBatchCheckC func (client *{{appShortName}}Client) ClientBatchCheckExecute(request SdkClientBatchCheckClientRequestInterface) (*ClientBatchCheckClientResponse, error) { group, ctx := errgroup.WithContext(request.GetContext()) - var maxParallelReqs int - if request.GetOptions() == nil || request.GetOptions().MaxParallelRequests == nil { - maxParallelReqs = int(DEFAULT_MAX_METHOD_PARALLEL_REQS) - } else { - maxParallelReqs = int(*request.GetOptions().MaxParallelRequests) + requestOptions := RequestOptions{} + maxParallelReqs := int(DEFAULT_MAX_METHOD_PARALLEL_REQS) + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + if request.GetOptions().MaxParallelRequests != nil { + maxParallelReqs = int(*request.GetOptions().MaxParallelRequests) + } } + group.SetLimit(maxParallelReqs) var numOfChecks = len(*request.GetBody()) response := make(ClientBatchCheckClientResponse, numOfChecks) @@ -2084,6 +2196,8 @@ func (client *{{appShortName}}Client) ClientBatchCheckExecute(request SdkClientB } checkOptions := &ClientCheckOptions{ + RequestOptions: requestOptions, + AuthorizationModelId: authorizationModelId, StoreId: storeId, } @@ -2259,9 +2373,10 @@ func (client *OpenFgaClient) singleBatchCheck(ctx _context.Context, body fgaSdk. return nil, err } - req := client.OpenFgaApi.BatchCheck(ctx, *storeId) - req = req.Body(body) - + req := client.OpenFgaApi. + BatchCheck(ctx, *storeId). + Body(body). + Options(options.RequestOptions) response, _, err := req.Execute() if err != nil { return nil, err @@ -2376,6 +2491,8 @@ type ClientExpandRequest struct { } type ClientExpandOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` @@ -2456,11 +2573,17 @@ func (client *{{appShortName}}Client) ExpandExecute(request SdkClientExpandReque AuthorizationModelId: authorizationModelId, } + requestOptions := RequestOptions{} if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi.Expand(request.GetContext(), *storeId).Body(body).Execute() + data, _, err := client.OpenFgaApi. + Expand(request.GetContext(), *storeId). + Body(body). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -2497,6 +2620,8 @@ type ClientListObjectsRequest struct { } type ClientListObjectsOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` @@ -2574,10 +2699,16 @@ func (client *{{appShortName}}Client) ListObjectsExecute(request SdkClientListOb Context: request.GetBody().Context, AuthorizationModelId: authorizationModelId, } + requestOptions := RequestOptions{} if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi.ListObjects(request.GetContext(), *storeId).Body(body).Execute() + data, _, err := client.OpenFgaApi. + ListObjects(request.GetContext(), *storeId). + Body(body). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -2615,10 +2746,12 @@ type ClientListRelationsRequest struct { } type ClientListRelationsOptions struct { - AuthorizationModelId *string `json:"authorization_model_id,omitempty"` - MaxParallelRequests *int32 `json:"max_parallel_requests,omitempty"` - StoreId *string `json:"store_id,omitempty"` - Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` + RequestOptions + + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` + MaxParallelRequests *int32 `json:"max_parallel_requests,omitempty"` + StoreId *string `json:"store_id,omitempty"` + Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` } type ClientListRelationsResponse struct { @@ -2707,6 +2840,7 @@ func (client *{{appShortName}}Client) ListRelationsExecute(request SdkClientList StoreId: storeId, } if request.GetOptions() != nil { + options.RequestOptions = request.GetOptions().RequestOptions options.Consistency = request.GetOptions().Consistency options.MaxParallelRequests = request.GetOptions().MaxParallelRequests } @@ -2763,9 +2897,11 @@ type ClientListUsersRequest struct { } type ClientListUsersOptions struct { - AuthorizationModelId *string `json:"authorization_model_id,omitempty"` - StoreId *string `json:"store_id,omitempty"` - Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` + RequestOptions + + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` + StoreId *string `json:"store_id,omitempty"` + Consistency *fgaSdk.ConsistencyPreference `json:"consistency,omitempty"` } type ClientListUsersResponse = fgaSdk.ListUsersResponse @@ -2841,11 +2977,17 @@ func (client *OpenFgaClient) ListUsersExecute(request SdkClientListUsersRequestI AuthorizationModelId: authorizationModelId, } + requestOptions := RequestOptions{} if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi.ListUsers(request.GetContext(), *storeId).Body(body).Execute() + data, _, err := client.OpenFgaApi. + ListUsers(request.GetContext(), *storeId). + Body(body). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -2871,6 +3013,8 @@ type SdkClientReadAssertionsRequestInterface interface { } type ClientReadAssertionsOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` } @@ -2927,7 +3071,16 @@ func (client *{{appShortName}}Client) ReadAssertionsExecute(request SdkClientRea if err != nil { return nil, err } - data, _, err := client.{{appShortName}}Api.ReadAssertions(request.GetContext(), *storeId, *authorizationModelId).Execute() + + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + data, _, err := client.{{appShortName}}Api. + ReadAssertions(request.GetContext(), *storeId, *authorizationModelId). + Options(requestOptions). + Execute() if err != nil { return nil, err } @@ -2986,6 +3139,8 @@ func (clientAssertion ClientAssertion) ToAssertion() fgaSdk.Assertion { } type ClientWriteAssertionsOptions struct { + RequestOptions + AuthorizationModelId *string `json:"authorization_model_id,omitempty"` StoreId *string `json:"store_id,omitempty"` } @@ -3057,7 +3212,17 @@ func (client *{{appShortName}}Client) WriteAssertionsExecute(request SdkClientWr clientAssertion := (*request.GetBody())[index] writeAssertionsRequest.Assertions = append(writeAssertionsRequest.Assertions, clientAssertion.ToAssertion()) } - _, err = client.{{appShortName}}Api.WriteAssertions(request.GetContext(), *storeId, *authorizationModelId).Body(writeAssertionsRequest).Execute() + + requestOptions := RequestOptions{} + if request.GetOptions() != nil { + requestOptions = request.GetOptions().RequestOptions + } + + _, err = client.{{appShortName}}Api. + WriteAssertions(request.GetContext(), *storeId, *authorizationModelId). + Body(writeAssertionsRequest). + Options(requestOptions). + Execute() if err != nil { return nil, err diff --git a/config/clients/go/template/client/client_headers_test.go b/config/clients/go/template/client/client_headers_test.go new file mode 100644 index 000000000..a0e9246c7 --- /dev/null +++ b/config/clients/go/template/client/client_headers_test.go @@ -0,0 +1,892 @@ +package client_test + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + + fgaSdk "github.com/openfga/go-sdk" + fgaSdkClient "github.com/openfga/go-sdk/client" +) + +// Test helpers and setup + +// Constants to avoid duplication +const ( + defaultHeaderName = "Default-Header" + defaultHeaderValue = "default-value" + overriddenValue = "overridden-value" + customHeaderName = "X-Custom-Header" + customHeaderValue = "custom-value" + testUser = "user:anne" + testRelation = "viewer" + testObject = "document:roadmap" + testHeaderName = "Test-Header" + testHeaderValue = "test-value" + checkRequestFailedMsg = "Check request failed: %v" + expectedCustomHeaderMsg = "Expected X-Custom-Header to be 'custom-value', got '%s'" + expectedOverriddenHeaderMsg = "Expected Default-Header to be overridden to 'overridden-value', got '%s'" + expectedDefaultHeaderMsg = "Expected Default-Header to be 'default-value', got '%s'" +) + +func createTestServer(t *testing.T, capturedHeaders *map[string]string, responseBody string) *httptest.Server { + t.Helper() + + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + *capturedHeaders = make(map[string]string) + for name, values := range r.Header { + if len(values) > 0 { + (*capturedHeaders)[name] = values[0] + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(responseBody)) + })) +} + +func createTestClient(t *testing.T, serverURL string, defaultHeaders map[string]string) *fgaSdkClient.OpenFgaClient { + t.Helper() + + config := fgaSdkClient.ClientConfiguration{ + ApiUrl: serverURL, + DefaultHeaders: defaultHeaders, + StoreId: "01H0H015178Y2V4CX10C2KGHF4", + HTTPClient: &http.Client{}, + } + + client, err := fgaSdkClient.NewSdkClient(&config) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + return client +} + +// Test RequestOptions +func TestRequestOptionsStructure(t *testing.T) { + t.Run("RequestOptionsEmbedding", func(t *testing.T) { + options := fgaSdkClient.ClientCheckOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + testHeaderName: testHeaderValue, + }, + MaxRetry: fgaSdk.PtrInt(3), + MinWaitInMs: fgaSdk.PtrInt(1000), + }, + AuthorizationModelId: fgaSdk.PtrString("01H0H015178Y2V4CX10C2KGHF4"), + Consistency: nil, + } + + if options.Headers[testHeaderName] != testHeaderValue { + t.Errorf("Expected %s to be '%s', got '%s'", testHeaderName, testHeaderValue, options.Headers[testHeaderName]) + } + + if options.MaxRetry == nil || *options.MaxRetry != 3 { + t.Errorf("Expected MaxRetry to be 3, got %v", options.MaxRetry) + } + + if options.MinWaitInMs == nil || *options.MinWaitInMs != 1000 { + t.Errorf("Expected MinWaitInMs to be 1000, got %v", options.MinWaitInMs) + } + + if options.AuthorizationModelId == nil || *options.AuthorizationModelId != "01H0H015178Y2V4CX10C2KGHF4" { + t.Errorf("Expected AuthorizationModelId to be set correctly") + } + }) + + t.Run("RequestWithNilHeaders", func(t *testing.T) { + options := fgaSdkClient.ClientCheckOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: nil, + MaxRetry: fgaSdk.PtrInt(3), + MinWaitInMs: fgaSdk.PtrInt(1000), + }, + } + + if options.Headers != nil { + t.Errorf("Expected Headers to be nil, got %v", options.Headers) + } + }) +} + +// Test the header handling for the methods + +func TestCheckMethodHeaderHandling(t *testing.T) { + t.Run("CheckWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Check(context.Background()). + Body(fgaSdkClient.ClientCheckRequest{ + User: testUser, + Relation: testRelation, + Object: testObject, + }). + Options(fgaSdkClient.ClientCheckOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("CheckWithoutCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Check(context.Background()). + Body(fgaSdkClient.ClientCheckRequest{ + User: testUser, + Relation: testRelation, + Object: testObject, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[defaultHeaderName] != defaultHeaderValue { + t.Errorf(expectedDefaultHeaderMsg, capturedHeaders[defaultHeaderName]) + } + + if _, exists := capturedHeaders[customHeaderName]; exists { + t.Error("Did not expect X-Custom-Header to be present") + } + }) + + t.Run("CheckWithEmptyHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createTestClient(t, server.URL, nil) + + _, err := client.Check(context.Background()). + Body(fgaSdkClient.ClientCheckRequest{ + User: testUser, + Relation: testRelation, + Object: testObject, + }). + Options(fgaSdkClient.ClientCheckOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{}, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + // Only standard headers should be present + for header := range capturedHeaders { + if strings.HasPrefix(header, "X-") || header == defaultHeaderName { + t.Errorf("Unexpected custom header found: %s", header) + } + } + }) + + t.Run("CheckWithNilOptions", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, `{"allowed": true}`) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + request := client.Check(context.Background()). + Body(fgaSdkClient.ClientCheckRequest{ + User: testUser, + Relation: testRelation, + Object: testObject, + }) + + // Options not set + _, err := request.Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[defaultHeaderName] != defaultHeaderValue { + t.Errorf(expectedDefaultHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestWriteMethodHeaderHandling(t *testing.T) { + const writeResponse = `{}` + + t.Run("WriteWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, writeResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Write(context.Background()). + Body(fgaSdkClient.ClientWriteRequest{ + Writes: []fgaSdkClient.ClientTupleKey{ + { + User: testUser, + Relation: testRelation, + Object: testObject, + }, + }, + }). + Options(fgaSdkClient.ClientWriteOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("WriteWithoutCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, writeResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Write(context.Background()). + Body(fgaSdkClient.ClientWriteRequest{ + Writes: []fgaSdkClient.ClientTupleKey{ + { + User: testUser, + Relation: testRelation, + Object: testObject, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[defaultHeaderName] != defaultHeaderValue { + t.Errorf(expectedDefaultHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestReadMethodHeaderHandling(t *testing.T) { + const readResponse = `{"tuples": []}` + + t.Run("ReadWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, readResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Read(context.Background()). + Body(fgaSdkClient.ClientReadRequest{ + User: fgaSdk.PtrString(testUser), + Relation: fgaSdk.PtrString(testRelation), + Object: fgaSdk.PtrString(testObject), + }). + Options(fgaSdkClient.ClientReadOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestExpandMethodHeaderHandling(t *testing.T) { + const expandResponse = `{"tree": {"root": {"name": "document:roadmap#viewer"}}}` + + t.Run("ExpandWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, expandResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.Expand(context.Background()). + Body(fgaSdkClient.ClientExpandRequest{ + Relation: testRelation, + Object: testObject, + }). + Options(fgaSdkClient.ClientExpandOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestListObjectsMethodHeaderHandling(t *testing.T) { + const listObjectsResponse = `{"objects": ["document:roadmap"]}` + + t.Run("ListObjectsWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, listObjectsResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ListObjects(context.Background()). + Body(fgaSdkClient.ClientListObjectsRequest{ + User: testUser, + Relation: testRelation, + Type: "document", + }). + Options(fgaSdkClient.ClientListObjectsOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestListUsersMethodHeaderHandling(t *testing.T) { + const listUsersResponse = `{"users": [{"object": {"type": "user", "id": "anne"}}]}` + + t.Run("ListUsersWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, listUsersResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ListUsers(context.Background()). + Body(fgaSdkClient.ClientListUsersRequest{ + Object: fgaSdk.FgaObject{ + Type: "document", + Id: "roadmap", + }, + Relation: testRelation, + UserFilters: []fgaSdk.UserTypeFilter{ + {Type: "user"}, + }, + }). + Options(fgaSdkClient.ClientListUsersOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestBatchCheckMethodHeaderHandling(t *testing.T) { + const batchCheckResponse = `[{"allowed": true}]` + + t.Run("BatchCheckWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, batchCheckResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + checks := []fgaSdkClient.ClientCheckRequest{ + { + User: testUser, + Relation: testRelation, + Object: testObject, + }, + } + + _, err := client.ClientBatchCheck(context.Background()). + Body(checks). + Options(fgaSdkClient.ClientBatchCheckClientOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestReadAuthorizationModelMethodHeaderHandling(t *testing.T) { + const authModelResponse = `{"authorization_model": {"id": "01H0H015178Y2V4CX10C2KGHF4", "schema_version": "1.1"}}` + + t.Run("ReadAuthorizationModelWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, authModelResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ReadAuthorizationModel(context.Background()). + Options(fgaSdkClient.ClientReadAuthorizationModelOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + AuthorizationModelId: fgaSdk.PtrString("01H0H015178Y2V4CX10C2KGHF4"), + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestWriteAuthorizationModelMethodHeaderHandling(t *testing.T) { + const writeAuthModelResponse = `{"authorization_model_id": "01H0H015178Y2V4CX10C2KGHF4"}` + + t.Run("WriteAuthorizationModelWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, writeAuthModelResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.WriteAuthorizationModel(context.Background()). + Body(fgaSdkClient.ClientWriteAuthorizationModelRequest{ + SchemaVersion: "1.1", + TypeDefinitions: []fgaSdk.TypeDefinition{ + { + Type: "user", + }, + { + Type: "document", + Relations: &map[string]fgaSdk.Userset{ + "viewer": {}, + }, + }, + }, + }). + Options(fgaSdkClient.ClientWriteAuthorizationModelOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestStoreMethodHeaderHandling(t *testing.T) { + t.Run("ListStoresWithCustomHeaders", func(t *testing.T) { + const listStoresResponse = `{"stores": [{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}]}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, listStoresResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ListStores(context.Background()). + Options(fgaSdkClient.ClientListStoresOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("CreateStoreWithCustomHeaders", func(t *testing.T) { + const createStoreResponse = `{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, createStoreResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.CreateStore(context.Background()). + Body(fgaSdkClient.ClientCreateStoreRequest{ + Name: "test", + }). + Options(fgaSdkClient.ClientCreateStoreOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("GetStoreWithCustomHeaders", func(t *testing.T) { + const getStoreResponse = `{"id": "01H0H015178Y2V4CX10C2KGHF4", "name": "test"}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, getStoreResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.GetStore(context.Background()). + Options(fgaSdkClient.ClientGetStoreOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("DeleteStoreWithCustomHeaders", func(t *testing.T) { + const deleteStoreResponse = `{}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, deleteStoreResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.DeleteStore(context.Background()). + Options(fgaSdkClient.ClientDeleteStoreOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestReadChangesMethodHeaderHandling(t *testing.T) { + const readChangesResponse = `{"changes": [], "continuation_token": ""}` + + t.Run("ReadChangesWithCustomHeaders", func(t *testing.T) { + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, readChangesResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ReadChanges(context.Background()). + Body(fgaSdkClient.ClientReadChangesRequest{ + Type: "document", + }). + Options(fgaSdkClient.ClientReadChangesOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} + +func TestAssertionsMethodHeaderHandling(t *testing.T) { + t.Run("ReadAssertionsWithCustomHeaders", func(t *testing.T) { + const readAssertionsResponse = `{"assertions": []}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, readAssertionsResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + _, err := client.ReadAssertions(context.Background()). + Options(fgaSdkClient.ClientReadAssertionsOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + AuthorizationModelId: fgaSdk.PtrString("01H0H015178Y2V4CX10C2KGHF4"), + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) + + t.Run("WriteAssertionsWithCustomHeaders", func(t *testing.T) { + const writeAssertionsResponse = `{}` + var capturedHeaders map[string]string + server := createTestServer(t, &capturedHeaders, writeAssertionsResponse) + defer server.Close() + + client := createTestClient(t, server.URL, map[string]string{ + defaultHeaderName: defaultHeaderValue, + }) + + assertions := []fgaSdkClient.ClientAssertion{ + { + User: testUser, + Relation: testRelation, + Object: testObject, + Expectation: true, + }, + } + + _, err := client.WriteAssertions(context.Background()). + Body(assertions). + Options(fgaSdkClient.ClientWriteAssertionsOptions{ + RequestOptions: fgaSdkClient.RequestOptions{ + Headers: map[string]string{ + customHeaderName: customHeaderValue, + defaultHeaderName: overriddenValue, + }, + }, + AuthorizationModelId: fgaSdk.PtrString("01H0H015178Y2V4CX10C2KGHF4"), + }). + Execute() + + if err != nil { + t.Fatalf(checkRequestFailedMsg, err) + } + + if capturedHeaders[customHeaderName] != customHeaderValue { + t.Errorf(expectedCustomHeaderMsg, capturedHeaders[customHeaderName]) + } + + if capturedHeaders[defaultHeaderName] != overriddenValue { + t.Errorf(expectedOverriddenHeaderMsg, capturedHeaders[defaultHeaderName]) + } + }) +} diff --git a/config/clients/go/template/example/example1/example1.go b/config/clients/go/template/example/example1/example1.go index 914b06950..3658664f4 100644 --- a/config/clients/go/template/example/example1/example1.go +++ b/config/clients/go/template/example/example1/example1.go @@ -254,6 +254,24 @@ func mainInner() error { } fmt.Printf("Allowed: %v\n", checkResponse.Allowed) + fmt.Println("Checking for access with custom headers") + checkWithHeadersResponse, err := fgaClient.Check(ctx).Body(client.ClientCheckRequest{ + User: "user:anne", + Relation: "viewer", + Object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + Context: &map[string]interface{}{"ViewCount": 100}, + }).Options(client.ClientCheckOptions{ + RequestOptions: client.RequestOptions{ + Headers: map[string]string{ + "X-Request-ID": "example-request-123", + }, + }, + }).Execute() + if err != nil { + return err + } + fmt.Printf("Allowed (with custom headers): %v\n", checkWithHeadersResponse.Allowed) + // BatchCheck fmt.Println("Batch checking for access") batchCheckResponse, err := fgaClient.BatchCheck(ctx).Body(client.ClientBatchCheckRequest{ From 0c6f157a1daedabd710624b32b4f361a5bfd189c Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Mon, 6 Oct 2025 15:03:35 -0400 Subject: [PATCH 2/5] chore(go): remove unused retry params from request options --- config/clients/go/template/api.mustache | 2 -- config/clients/go/template/api_headers_test.go | 18 ++---------------- .../go/template/client/client_headers_test.go | 14 +------------- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/config/clients/go/template/api.mustache b/config/clients/go/template/api.mustache index e12ef404f..cec889600 100644 --- a/config/clients/go/template/api.mustache +++ b/config/clients/go/template/api.mustache @@ -25,8 +25,6 @@ var ( {{#generateInterfaces}} type RequestOptions struct { - MaxRetry *int `json:"max_retry,omitempty"` - MinWaitInMs *int `json:"min_wait_in_ms,omitempty"` Headers map[string]string `json:"headers,omitempty"` } diff --git a/config/clients/go/template/api_headers_test.go b/config/clients/go/template/api_headers_test.go index 5cc990730..c5dc75611 100644 --- a/config/clients/go/template/api_headers_test.go +++ b/config/clients/go/template/api_headers_test.go @@ -71,28 +71,16 @@ func TestAPIRequestOptionsStructure(t *testing.T) { Headers: map[string]string{ "Test-Header": "test-value", }, - MaxRetry: openfga.PtrInt(3), - MinWaitInMs: openfga.PtrInt(1000), } if options.Headers["Test-Header"] != "test-value" { t.Errorf("Expected Test-Header to be 'test-value', got '%s'", options.Headers["Test-Header"]) } - - if options.MaxRetry == nil || *options.MaxRetry != 3 { - t.Errorf("Expected MaxRetry to be 3, got %v", options.MaxRetry) - } - - if options.MinWaitInMs == nil || *options.MinWaitInMs != 1000 { - t.Errorf("Expected MinWaitInMs to be 1000, got %v", options.MinWaitInMs) - } }) t.Run("RequestOptionsWithNilHeaders", func(t *testing.T) { options := openfga.RequestOptions{ - Headers: nil, - MaxRetry: openfga.PtrInt(3), - MinWaitInMs: openfga.PtrInt(1000), + Headers: nil, } if options.Headers != nil { @@ -102,9 +90,7 @@ func TestAPIRequestOptionsStructure(t *testing.T) { t.Run("RequestOptionsWithEmptyHeaders", func(t *testing.T) { options := openfga.RequestOptions{ - Headers: map[string]string{}, - MaxRetry: openfga.PtrInt(3), - MinWaitInMs: openfga.PtrInt(1000), + Headers: map[string]string{}, } if len(options.Headers) != 0 { diff --git a/config/clients/go/template/client/client_headers_test.go b/config/clients/go/template/client/client_headers_test.go index a0e9246c7..e0d73c1f7 100644 --- a/config/clients/go/template/client/client_headers_test.go +++ b/config/clients/go/template/client/client_headers_test.go @@ -74,8 +74,6 @@ func TestRequestOptionsStructure(t *testing.T) { Headers: map[string]string{ testHeaderName: testHeaderValue, }, - MaxRetry: fgaSdk.PtrInt(3), - MinWaitInMs: fgaSdk.PtrInt(1000), }, AuthorizationModelId: fgaSdk.PtrString("01H0H015178Y2V4CX10C2KGHF4"), Consistency: nil, @@ -85,14 +83,6 @@ func TestRequestOptionsStructure(t *testing.T) { t.Errorf("Expected %s to be '%s', got '%s'", testHeaderName, testHeaderValue, options.Headers[testHeaderName]) } - if options.MaxRetry == nil || *options.MaxRetry != 3 { - t.Errorf("Expected MaxRetry to be 3, got %v", options.MaxRetry) - } - - if options.MinWaitInMs == nil || *options.MinWaitInMs != 1000 { - t.Errorf("Expected MinWaitInMs to be 1000, got %v", options.MinWaitInMs) - } - if options.AuthorizationModelId == nil || *options.AuthorizationModelId != "01H0H015178Y2V4CX10C2KGHF4" { t.Errorf("Expected AuthorizationModelId to be set correctly") } @@ -101,9 +91,7 @@ func TestRequestOptionsStructure(t *testing.T) { t.Run("RequestWithNilHeaders", func(t *testing.T) { options := fgaSdkClient.ClientCheckOptions{ RequestOptions: fgaSdkClient.RequestOptions{ - Headers: nil, - MaxRetry: fgaSdk.PtrInt(3), - MinWaitInMs: fgaSdk.PtrInt(1000), + Headers: nil, }, } From bb78fac78feeb87c3f8d01b9409893cb3cd8a4d6 Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Tue, 7 Oct 2025 09:21:09 -0400 Subject: [PATCH 3/5] chore(go): use BatchCheck in headers test instead of ClientBatchCheck --- .../go/template/client/client_headers_test.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/config/clients/go/template/client/client_headers_test.go b/config/clients/go/template/client/client_headers_test.go index e0d73c1f7..8e9c50699 100644 --- a/config/clients/go/template/client/client_headers_test.go +++ b/config/clients/go/template/client/client_headers_test.go @@ -482,7 +482,7 @@ func TestListUsersMethodHeaderHandling(t *testing.T) { } func TestBatchCheckMethodHeaderHandling(t *testing.T) { - const batchCheckResponse = `[{"allowed": true}]` + const batchCheckResponse = `{"result":{"corr-id-123":{"allowed": true}}}` t.Run("BatchCheckWithCustomHeaders", func(t *testing.T) { var capturedHeaders map[string]string @@ -493,17 +493,18 @@ func TestBatchCheckMethodHeaderHandling(t *testing.T) { defaultHeaderName: defaultHeaderValue, }) - checks := []fgaSdkClient.ClientCheckRequest{ - { + checks := fgaSdkClient.ClientBatchCheckRequest{ + Checks: []fgaSdkClient.ClientBatchCheckItem{{ + CorrelationId: "corr-id-123", User: testUser, Relation: testRelation, Object: testObject, - }, + }}, } - _, err := client.ClientBatchCheck(context.Background()). + _, err := client.BatchCheck(context.Background()). Body(checks). - Options(fgaSdkClient.ClientBatchCheckClientOptions{ + Options(fgaSdkClient.BatchCheckOptions{ RequestOptions: fgaSdkClient.RequestOptions{ Headers: map[string]string{ customHeaderName: customHeaderValue, From f426bc25481b52c1009adb159f23a961644b8a6e Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Tue, 7 Oct 2025 10:02:46 -0400 Subject: [PATCH 4/5] chore(go): fix templating in client --- .../go/template/client/client.mustache | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/config/clients/go/template/client/client.mustache b/config/clients/go/template/client/client.mustache index fb51e7614..bf20c583b 100644 --- a/config/clients/go/template/client/client.mustache +++ b/config/clients/go/template/client/client.mustache @@ -469,28 +469,28 @@ type SdkClient interface { WriteAssertionsExecute(request SdkClientWriteAssertionsRequestInterface) (*ClientWriteAssertionsResponse, error) /* - * SetAuthorizationModelId allows setting the Authorization Model ID for an OpenFGAClient. + * SetAuthorizationModelId allows setting the Authorization Model ID for an {{appShortName}}Client. * @param string authorizationModelId - The Authorization Model ID to set. */ SetAuthorizationModelId(authorizationModelId string) error /* - * GetAuthorizationModelId retrieves the Authorization Model ID for an OpenFGAClient. + * GetAuthorizationModelId retrieves the Authorization Model ID for an {{appShortName}}Client. * @return string */ GetAuthorizationModelId() (string, error) /* - * SetStoreId allows setting the Store ID for an OpenFGAClient. + * SetStoreId allows setting the Store ID for an {{appShortName}}Client. * @param string storeId - The Store ID to set. */ SetStoreId(storeId string) error /* - * GetStoreId retrieves the Store ID set in the OpenFGAClient. + * GetStoreId retrieves the Store ID set in the {{appShortName}}Client. * @return string */ GetStoreId() (string, error) } -func (client *OpenFgaClient) SetAuthorizationModelId(authorizationModelId string) error { +func (client *{{appShortName}}Client) SetAuthorizationModelId(authorizationModelId string) error { if authorizationModelId != "" && !internalutils.IsWellFormedUlidString(authorizationModelId) { return FgaInvalidError{param: "AuthorizationModelId", description: "Expected ULID format"} } @@ -500,7 +500,7 @@ func (client *OpenFgaClient) SetAuthorizationModelId(authorizationModelId string return nil } -func (client *OpenFgaClient) GetAuthorizationModelId() (string, error) { +func (client *{{appShortName}}Client) GetAuthorizationModelId() (string, error) { modelId := client.config.AuthorizationModelId if modelId != "" && !internalutils.IsWellFormedUlidString(modelId) { return "", FgaInvalidError{param: "AuthorizationModelId", description: "Expected ULID format"} @@ -521,7 +521,7 @@ func (client *{{appShortName}}Client) getAuthorizationModelId(authorizationModel return &modelId, nil } -func (client *OpenFgaClient) SetStoreId(storeId string) error { +func (client *{{appShortName}}Client) SetStoreId(storeId string) error { if storeId != "" && !internalutils.IsWellFormedUlidString(storeId) { return FgaInvalidError{param: "StoreId", description: "Expected ULID format"} } @@ -529,7 +529,7 @@ func (client *OpenFgaClient) SetStoreId(storeId string) error { return nil } -func (client *OpenFgaClient) GetStoreId() (string, error) { +func (client *{{appShortName}}Client) GetStoreId() (string, error) { storeId := client.config.StoreId if storeId != "" && !internalutils.IsWellFormedUlidString(storeId) { return "", FgaInvalidError{param: "StoreId", description: "Expected ULID format"} @@ -539,7 +539,7 @@ func (client *OpenFgaClient) GetStoreId() (string, error) { -func (client *OpenFgaClient) getStoreId(storeId *string) (*string, error) { +func (client *{{appShortName}}Client) getStoreId(storeId *string) (*string, error) { store := client.config.StoreId if storeId != nil && *storeId != "" { store = *storeId @@ -2241,7 +2241,7 @@ func (client *{{appShortName}}Client) ClientBatchCheckExecute(request SdkClientB // SdkClientBatchCheckRequest represents a server-side batch check request type SdkClientBatchCheckRequest struct { ctx _context.Context - client *OpenFgaClient + client *{{appShortName}}Client body *ClientBatchCheckRequest options *BatchCheckOptions } @@ -2283,7 +2283,7 @@ func (r *SdkClientBatchCheckRequest) GetOptions() *BatchCheckOptions { } // BatchCheck initializes a new batch check request -func (client *OpenFgaClient) BatchCheck(ctx _context.Context) SdkClientBatchCheckRequestInterface { +func (client *{{appShortName}}Client) BatchCheck(ctx _context.Context) SdkClientBatchCheckRequestInterface { return &SdkClientBatchCheckRequest{ ctx: ctx, client: client, @@ -2295,7 +2295,7 @@ func (client *OpenFgaClient) BatchCheck(ctx _context.Context) SdkClientBatchChec * @param request SdkClientBatchCheckRequestInterface - the request interface * @return *fgaSdk.BatchCheckResponse */ -func (client *OpenFgaClient) BatchCheckExecute(request SdkClientBatchCheckRequestInterface) (*fgaSdk.BatchCheckResponse, error) { +func (client *{{appShortName}}Client) BatchCheckExecute(request SdkClientBatchCheckRequestInterface) (*fgaSdk.BatchCheckResponse, error) { ctx := request.GetContext() body := request.GetBody() options := request.GetOptions() @@ -2367,13 +2367,13 @@ func (client *OpenFgaClient) BatchCheckExecute(request SdkClientBatchCheckReques * @param options *BatchCheckOptions - options for the request * @return *fgaSdk.BatchCheckResponse */ -func (client *OpenFgaClient) singleBatchCheck(ctx _context.Context, body fgaSdk.BatchCheckRequest, options *BatchCheckOptions) (*fgaSdk.BatchCheckResponse, error) { +func (client *{{appShortName}}Client) singleBatchCheck(ctx _context.Context, body fgaSdk.BatchCheckRequest, options *BatchCheckOptions) (*fgaSdk.BatchCheckResponse, error) { storeId, err := client.getStoreId(options.StoreId) if err != nil { return nil, err } - req := client.OpenFgaApi. + req := client.{{appShortName}}Api. BatchCheck(ctx, *storeId). Body(body). Options(options.RequestOptions) @@ -2579,7 +2579,7 @@ func (client *{{appShortName}}Client) ExpandExecute(request SdkClientExpandReque body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi. + data, _, err := client.{{appShortName}}Api. Expand(request.GetContext(), *storeId). Body(body). Options(requestOptions). @@ -2704,7 +2704,7 @@ func (client *{{appShortName}}Client) ListObjectsExecute(request SdkClientListOb requestOptions = request.GetOptions().RequestOptions body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi. + data, _, err := client.{{appShortName}}Api. ListObjects(request.GetContext(), *storeId). Body(body). Options(requestOptions). @@ -2869,7 +2869,7 @@ func (client *{{appShortName}}Client) ListRelationsExecute(request SdkClientList // / ListUsers type SdkClientListUsersRequest struct { ctx _context.Context - Client *OpenFgaClient + Client *{{appShortName}}Client body *ClientListUsersRequest options *ClientListUsersOptions @@ -2906,7 +2906,7 @@ type ClientListUsersOptions struct { type ClientListUsersResponse = fgaSdk.ListUsersResponse -func (client *OpenFgaClient) ListUsers(ctx _context.Context) SdkClientListUsersRequestInterface { +func (client *{{appShortName}}Client) ListUsers(ctx _context.Context) SdkClientListUsersRequestInterface { return &SdkClientListUsersRequest{ Client: client, ctx: ctx, @@ -2953,7 +2953,7 @@ func (request *SdkClientListUsersRequest) GetOptions() *ClientListUsersOptions { return request.options } -func (client *OpenFgaClient) ListUsersExecute(request SdkClientListUsersRequestInterface) (*ClientListUsersResponse, error) { +func (client *{{appShortName}}Client) ListUsersExecute(request SdkClientListUsersRequestInterface) (*ClientListUsersResponse, error) { var contextualTuples []ClientContextualTupleKey if request.GetBody().ContextualTuples != nil { for index := 0; index < len(request.GetBody().ContextualTuples); index++ { @@ -2983,7 +2983,7 @@ func (client *OpenFgaClient) ListUsersExecute(request SdkClientListUsersRequestI body.Consistency = request.GetOptions().Consistency } - data, _, err := client.OpenFgaApi. + data, _, err := client.{{appShortName}}Api. ListUsers(request.GetContext(), *storeId). Body(body). Options(requestOptions). From e1447afb1042af8f927b52a5c8ebe188c084dddf Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Tue, 7 Oct 2025 10:19:50 -0400 Subject: [PATCH 5/5] chore(go): bump dependency --- config/clients/go/template/go.mod.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/clients/go/template/go.mod.mustache b/config/clients/go/template/go.mod.mustache index ac173c8ce..a9f3d0dbc 100644 --- a/config/clients/go/template/go.mod.mustache +++ b/config/clients/go/template/go.mod.mustache @@ -9,5 +9,5 @@ require ( github.com/sourcegraph/conc v0.3.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 - golang.org/x/sync v0.16.0 + golang.org/x/sync v0.17.0 )