From 7940976ea0eb608b45e86c32f453bc02cc14f9b4 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Mon, 16 Dec 2024 16:49:19 -0800 Subject: [PATCH 1/4] add golang to relay server (FF-3495) --- .github/workflows/test-sdk-packages.yml | 12 ++ package-testing/go-sdk-relay/.gitignore | 2 + package-testing/go-sdk-relay/Dockerfile | 18 +++ package-testing/go-sdk-relay/README.md | 29 ++++ package-testing/go-sdk-relay/docker-run.sh | 29 ++++ package-testing/go-sdk-relay/go.mod | 12 ++ package-testing/go-sdk-relay/go.sum | 10 ++ package-testing/go-sdk-relay/main.go | 179 +++++++++++++++++++++ 8 files changed, 291 insertions(+) create mode 100644 package-testing/go-sdk-relay/.gitignore create mode 100644 package-testing/go-sdk-relay/Dockerfile create mode 100644 package-testing/go-sdk-relay/README.md create mode 100755 package-testing/go-sdk-relay/docker-run.sh create mode 100644 package-testing/go-sdk-relay/go.mod create mode 100644 package-testing/go-sdk-relay/go.sum create mode 100644 package-testing/go-sdk-relay/main.go diff --git a/.github/workflows/test-sdk-packages.yml b/.github/workflows/test-sdk-packages.yml index 4086ee1..fd96c96 100644 --- a/.github/workflows/test-sdk-packages.yml +++ b/.github/workflows/test-sdk-packages.yml @@ -43,3 +43,15 @@ jobs: sdkName: 'eppo/ruby-sdk' sdkRelayDir: 'ruby-sdk-relay' secrets: inherit + + test-go-sdk: + strategy: + fail-fast: false + matrix: + platform: ['linux'] + uses: ./.github/workflows/test-server-sdk.yml + with: + platform: ${{ matrix.platform }} + sdkName: 'eppo/go-sdk' + sdkRelayDir: 'go-sdk-relay' + secrets: inherit diff --git a/package-testing/go-sdk-relay/.gitignore b/package-testing/go-sdk-relay/.gitignore new file mode 100644 index 0000000..51a41ee --- /dev/null +++ b/package-testing/go-sdk-relay/.gitignore @@ -0,0 +1,2 @@ +.env +bin/ diff --git a/package-testing/go-sdk-relay/Dockerfile b/package-testing/go-sdk-relay/Dockerfile new file mode 100644 index 0000000..42bf96b --- /dev/null +++ b/package-testing/go-sdk-relay/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.23 + +WORKDIR /app + +# Copy go mod and sum files +COPY . . + +# Download all dependencies +RUN go mod download + +# Copy the source code +COPY . . + +# Build the application +RUN go build -o main . + +# Run the application +CMD ["./main"] diff --git a/package-testing/go-sdk-relay/README.md b/package-testing/go-sdk-relay/README.md new file mode 100644 index 0000000..f157196 --- /dev/null +++ b/package-testing/go-sdk-relay/README.md @@ -0,0 +1,29 @@ +# Go Testing Server + +Post test case files to this server and check the results against what's expected. + +## Running locally with Docker + +Build the docker image: + +```shell +docker build -t Eppo-exp/go-sdk-relay . +``` + +Run the docker container: + +```shell +./docker-run.sh +``` + +## Development + +1. Install dependencies: +```shell +go mod download +``` + +2. Run the server: +```shell +go run main.go +``` diff --git a/package-testing/go-sdk-relay/docker-run.sh b/package-testing/go-sdk-relay/docker-run.sh new file mode 100755 index 0000000..94a8a89 --- /dev/null +++ b/package-testing/go-sdk-relay/docker-run.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Default is to use the latest build +VERSION="${1:-latest}" + +echo "Starting deployment with version: $VERSION" + +if [ -e .env ]; then + echo "Loading environment variables from .env file" + source .env +fi + +echo "Stopping existing container..." +docker stop go-relay +echo "Removing existing container..." +docker remove go-relay + +echo "Building new image..." +docker build . -t Eppo-exp/go-sdk-relay:$VERSION + +echo "Starting new container..." +docker run -p $SDK_RELAY_PORT:$SDK_RELAY_PORT \ + --add-host host.docker.internal:host-gateway \ + -e SDK_REF \ + -e EPPO_BASE_URL \ + -e SDK_RELAY_PORT \ + --name go-relay \ + --rm \ + -t Eppo-exp/go-sdk-relay:$VERSION \ No newline at end of file diff --git a/package-testing/go-sdk-relay/go.mod b/package-testing/go-sdk-relay/go.mod new file mode 100644 index 0000000..324fe2f --- /dev/null +++ b/package-testing/go-sdk-relay/go.mod @@ -0,0 +1,12 @@ +module github.com/eppo/go-sdk-relay + +go 1.23.1 + +require github.com/Eppo-exp/golang-sdk/v6 v6.1.0 + +require ( + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect +) diff --git a/package-testing/go-sdk-relay/go.sum b/package-testing/go-sdk-relay/go.sum new file mode 100644 index 0000000..954c4ec --- /dev/null +++ b/package-testing/go-sdk-relay/go.sum @@ -0,0 +1,10 @@ +github.com/Eppo-exp/golang-sdk/v6 v6.1.0 h1:a9nEXYnc/r4cNRMeV8CHc1c/VXbcXS5KiFPDpsTDTH8= +github.com/Eppo-exp/golang-sdk/v6 v6.1.0/go.mod h1:UZ385Go97q/BmPG4wsnaSGbdQE4LAiIo25oQVbJrm20= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= diff --git a/package-testing/go-sdk-relay/main.go b/package-testing/go-sdk-relay/main.go new file mode 100644 index 0000000..5e04ea0 --- /dev/null +++ b/package-testing/go-sdk-relay/main.go @@ -0,0 +1,179 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "os" + "strconv" + "time" + + "github.com/Eppo-exp/golang-sdk/v6/eppoclient" +) + +type AssignmentRequest struct { + Flag string `json:"flag"` + SubjectKey string `json:"subjectKey"` + SubjectAttributes map[string]interface{} `json:"subjectAttributes"` + AssignmentType string `json:"assignmentType"` + DefaultValue interface{} `json:"defaultValue"` +} + +type AssignmentResponse struct { + Result interface{} `json:"result"` + AssignmentLog []string `json:"assignmentLog"` + BanditLog []string `json:"banditLog"` + Error *string `json:"error"` +} + +type SDKDetails struct { + SDKName string `json:"sdkName"` + SDKVersion string `json:"sdkVersion"` + SupportsBandits bool `json:"supportsBandits"` + SupportsDynamicTyping bool `json:"supportsDynamicTyping"` +} + +var eppoClient = &eppoclient.EppoClient{} + +func initializeClient() error { + apiKey := os.Getenv("EPPO_API_KEY") + if apiKey == "" { + apiKey = "NOKEYSPECIFIED" + } + + baseURL := os.Getenv("EPPO_BASE_URL") + if baseURL == "" { + baseURL = "http://localhost:5000/api" + } + + client, err := eppoclient.InitClient(eppoclient.Config{ + SdkKey: apiKey, + BaseUrl: baseURL, + }) + if err != nil { + return fmt.Errorf("failed to create client: %v", err) + } + + eppoClient = client + + select { + case <-client.Initialized(): + case <-time.After(3 * time.Second): + log.Printf("Timed out waiting for Eppo SDK to initialize") + } + + return nil +} + +func handleHealthCheck(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, "OK") +} + +func handleSDKDetails(w http.ResponseWriter, r *http.Request) { + details := SDKDetails{ + SDKName: "go-sdk", + SDKVersion: "1.0.0", + SupportsBandits: false, + SupportsDynamicTyping: false, + } + json.NewEncoder(w).Encode(details) +} + +func handleReset(w http.ResponseWriter, r *http.Request) { + err := initializeClient() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + fmt.Fprint(w, "Reset complete") +} + +func handleAssignment(w http.ResponseWriter, r *http.Request) { + var req AssignmentRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + var result interface{} + var err error + + switch req.AssignmentType { + case "BOOLEAN": + defaultVal, _ := req.DefaultValue.(bool) + result, err = eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + + case "STRING": + defaultVal, _ := req.DefaultValue.(string) + result, err = eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + + case "NUMERIC": + defaultVal, _ := strconv.ParseFloat(fmt.Sprintf("%v", req.DefaultValue), 64) + result, err = eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + + case "INTEGER": + defaultVal, _ := req.DefaultValue.(float64) + result, err = eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, int64(defaultVal)) + + case "JSON": + result, err = eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) + + default: + errMsg := fmt.Sprintf("unsupported assignment type: %s", req.AssignmentType) + http.Error(w, errMsg, http.StatusBadRequest) + return + } + + response := AssignmentResponse{ + Result: result, + AssignmentLog: []string{}, + BanditLog: []string{}, + } + + if err != nil { + errStr := err.Error() + response.Error = &errStr + response.Result = nil + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func handleBanditAction(w http.ResponseWriter, r *http.Request) { + // TODO: Implement bandit logic + response := AssignmentResponse{ + Result: "action", + AssignmentLog: []string{}, + BanditLog: []string{}, + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func main() { + if err := initializeClient(); err != nil { + log.Fatalf("Failed to initialize client: %v", err) + } + + http.HandleFunc("/", handleHealthCheck) + http.HandleFunc("/sdk/details", handleSDKDetails) + http.HandleFunc("/sdk/reset", handleReset) + http.HandleFunc("/flags/v1/assignment", handleAssignment) + http.HandleFunc("/bandits/v1/action", handleBanditAction) + + port := os.Getenv("SDK_RELAY_PORT") + if port == "" { + port = "7001" + } + + host := os.Getenv("SDK_RELAY_HOST") + if host == "" { + host = "0.0.0.0" + } + + addr := fmt.Sprintf("%s:%s", host, port) + log.Printf("Starting server on %s", addr) + log.Fatal(http.ListenAndServe(addr, nil)) +} From 539472a6f2ec6c68a24a916c04f931712b579c10 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Mon, 16 Dec 2024 16:54:59 -0800 Subject: [PATCH 2/4] init --- package-testing/go-sdk-relay/docker-run.sh | 2 +- package-testing/go-sdk-relay/main.go | 98 ++++++++++++++++------ 2 files changed, 74 insertions(+), 26 deletions(-) diff --git a/package-testing/go-sdk-relay/docker-run.sh b/package-testing/go-sdk-relay/docker-run.sh index 94a8a89..163b7a1 100755 --- a/package-testing/go-sdk-relay/docker-run.sh +++ b/package-testing/go-sdk-relay/docker-run.sh @@ -26,4 +26,4 @@ docker run -p $SDK_RELAY_PORT:$SDK_RELAY_PORT \ -e SDK_RELAY_PORT \ --name go-relay \ --rm \ - -t Eppo-exp/go-sdk-relay:$VERSION \ No newline at end of file + -t Eppo-exp/go-sdk-relay:$VERSION diff --git a/package-testing/go-sdk-relay/main.go b/package-testing/go-sdk-relay/main.go index 5e04ea0..daa4c1f 100644 --- a/package-testing/go-sdk-relay/main.go +++ b/package-testing/go-sdk-relay/main.go @@ -34,7 +34,7 @@ type SDKDetails struct { SupportsDynamicTyping bool `json:"supportsDynamicTyping"` } -var eppoClient = &eppoclient.EppoClient{} +var eppoClient *eppoclient.EppoClient func initializeClient() error { apiKey := os.Getenv("EPPO_API_KEY") @@ -47,22 +47,33 @@ func initializeClient() error { baseURL = "http://localhost:5000/api" } - client, err := eppoclient.InitClient(eppoclient.Config{ + // Create configuration + config := eppoclient.Config{ SdkKey: apiKey, BaseUrl: baseURL, - }) + } + + // Initialize client + client, err := eppoclient.InitClient(config) if err != nil { return fmt.Errorf("failed to create client: %v", err) } - eppoClient = client + // Wait for initialization with timeout + initChan := make(chan struct{}) + go func() { + <-client.Initialized() + close(initChan) + }() select { - case <-client.Initialized(): - case <-time.After(3 * time.Second): - log.Printf("Timed out waiting for Eppo SDK to initialize") + case <-initChan: + log.Printf("Eppo client initialized successfully") + case <-time.After(5 * time.Second): + log.Printf("Warning: Timed out waiting for Eppo SDK to initialize") } + eppoClient = client return nil } @@ -73,7 +84,7 @@ func handleHealthCheck(w http.ResponseWriter, r *http.Request) { func handleSDKDetails(w http.ResponseWriter, r *http.Request) { details := SDKDetails{ SDKName: "go-sdk", - SDKVersion: "1.0.0", + SDKVersion: "6.1.0", SupportsBandits: false, SupportsDynamicTyping: false, } @@ -96,45 +107,82 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { return } - var result interface{} + // Always prepare a response with default values + response := AssignmentResponse{ + Result: req.DefaultValue, + AssignmentLog: []string{}, + BanditLog: []string{}, + } + + // Check if client is nil or not initialized + if eppoClient == nil { + errStr := "client not initialized" + response.Error = &errStr + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + return + } + var err error + defer func() { + if r := recover(); r != nil { + errStr := fmt.Sprintf("panic recovered: %v", r) + response.Error = &errStr + response.Result = req.DefaultValue + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + } + }() switch req.AssignmentType { case "BOOLEAN": defaultVal, _ := req.DefaultValue.(bool) - result, err = eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result, err = eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) case "STRING": defaultVal, _ := req.DefaultValue.(string) - result, err = eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result, err = eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) case "NUMERIC": - defaultVal, _ := strconv.ParseFloat(fmt.Sprintf("%v", req.DefaultValue), 64) - result, err = eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + var defaultVal float64 + switch v := req.DefaultValue.(type) { + case float64: + defaultVal = v + case int: + defaultVal = float64(v) + case string: + defaultVal, _ = strconv.ParseFloat(v, 64) + } + response.Result, err = eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) case "INTEGER": - defaultVal, _ := req.DefaultValue.(float64) - result, err = eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, int64(defaultVal)) + var defaultVal int64 + switch v := req.DefaultValue.(type) { + case float64: + defaultVal = int64(v) + case int: + defaultVal = int64(v) + case string: + val, _ := strconv.ParseInt(v, 10, 64) + defaultVal = val + } + response.Result, err = eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) case "JSON": - result, err = eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) + response.Result, err = eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) default: - errMsg := fmt.Sprintf("unsupported assignment type: %s", req.AssignmentType) - http.Error(w, errMsg, http.StatusBadRequest) + errStr := fmt.Sprintf("unsupported assignment type: %s", req.AssignmentType) + response.Error = &errStr + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) return } - response := AssignmentResponse{ - Result: result, - AssignmentLog: []string{}, - BanditLog: []string{}, - } - if err != nil { errStr := err.Error() response.Error = &errStr - response.Result = nil + response.Result = req.DefaultValue } w.Header().Set("Content-Type", "application/json") From f7ab14a02aa38c8f2fa98bfa20e8de075184637b Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Mon, 16 Dec 2024 17:00:04 -0800 Subject: [PATCH 3/4] default --- package-testing/go-sdk-relay/main.go | 61 ++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/package-testing/go-sdk-relay/main.go b/package-testing/go-sdk-relay/main.go index daa4c1f..021d8df 100644 --- a/package-testing/go-sdk-relay/main.go +++ b/package-testing/go-sdk-relay/main.go @@ -114,7 +114,6 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { BanditLog: []string{}, } - // Check if client is nil or not initialized if eppoClient == nil { errStr := "client not initialized" response.Error = &errStr @@ -136,15 +135,33 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { switch req.AssignmentType { case "BOOLEAN": - defaultVal, _ := req.DefaultValue.(bool) - response.Result, err = eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + defaultVal := false + if v, ok := req.DefaultValue.(bool); ok { + defaultVal = v + } else if v, ok := req.DefaultValue.(float64); ok { + defaultVal = v != 0 + } + result, err := eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + if err != nil { + response.Result = defaultVal + } else { + response.Result = result + } case "STRING": - defaultVal, _ := req.DefaultValue.(string) - response.Result, err = eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + defaultVal := "" + if v, ok := req.DefaultValue.(string); ok { + defaultVal = v + } + result, err := eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + if err != nil { + response.Result = defaultVal + } else { + response.Result = result + } case "NUMERIC": - var defaultVal float64 + defaultVal := 0.0 switch v := req.DefaultValue.(type) { case float64: defaultVal = v @@ -153,36 +170,46 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { case string: defaultVal, _ = strconv.ParseFloat(v, 64) } - response.Result, err = eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + result, err := eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + if err != nil { + response.Result = defaultVal + } else { + response.Result = result + } case "INTEGER": - var defaultVal int64 + defaultVal := int64(0) switch v := req.DefaultValue.(type) { case float64: defaultVal = int64(v) case int: defaultVal = int64(v) - case string: - val, _ := strconv.ParseInt(v, 10, 64) - defaultVal = val + case int64: + defaultVal = v + } + result, err := eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + if err != nil { + response.Result = float64(defaultVal) // Convert to float64 for JSON consistency + } else { + response.Result = float64(result) // Convert to float64 for JSON consistency } - response.Result, err = eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) case "JSON": - response.Result, err = eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) + result, err := eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) + if err != nil { + response.Result = req.DefaultValue + } else { + response.Result = result + } default: errStr := fmt.Sprintf("unsupported assignment type: %s", req.AssignmentType) response.Error = &errStr - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) - return } if err != nil { errStr := err.Error() response.Error = &errStr - response.Result = req.DefaultValue } w.Header().Set("Content-Type", "application/json") From 22552197b7944722c4840509b94839d638de5875 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Mon, 16 Dec 2024 17:04:40 -0800 Subject: [PATCH 4/4] default2 --- package-testing/go-sdk-relay/main.go | 42 ++++++++-------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/package-testing/go-sdk-relay/main.go b/package-testing/go-sdk-relay/main.go index 021d8df..9f116ca 100644 --- a/package-testing/go-sdk-relay/main.go +++ b/package-testing/go-sdk-relay/main.go @@ -109,7 +109,7 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { // Always prepare a response with default values response := AssignmentResponse{ - Result: req.DefaultValue, + Result: nil, AssignmentLog: []string{}, BanditLog: []string{}, } @@ -141,24 +141,16 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { } else if v, ok := req.DefaultValue.(float64); ok { defaultVal = v != 0 } - result, err := eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) - if err != nil { - response.Result = defaultVal - } else { - response.Result = result - } + result, _ := eppoClient.GetBoolAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result = result case "STRING": defaultVal := "" if v, ok := req.DefaultValue.(string); ok { defaultVal = v } - result, err := eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) - if err != nil { - response.Result = defaultVal - } else { - response.Result = result - } + result, _ := eppoClient.GetStringAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result = result case "NUMERIC": defaultVal := 0.0 @@ -170,12 +162,8 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { case string: defaultVal, _ = strconv.ParseFloat(v, 64) } - result, err := eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) - if err != nil { - response.Result = defaultVal - } else { - response.Result = result - } + result, _ := eppoClient.GetNumericAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result = result case "INTEGER": defaultVal := int64(0) @@ -187,20 +175,12 @@ func handleAssignment(w http.ResponseWriter, r *http.Request) { case int64: defaultVal = v } - result, err := eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) - if err != nil { - response.Result = float64(defaultVal) // Convert to float64 for JSON consistency - } else { - response.Result = float64(result) // Convert to float64 for JSON consistency - } + result, _ := eppoClient.GetIntegerAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, defaultVal) + response.Result = float64(result) case "JSON": - result, err := eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) - if err != nil { - response.Result = req.DefaultValue - } else { - response.Result = result - } + result, _ := eppoClient.GetJSONAssignment(req.Flag, req.SubjectKey, req.SubjectAttributes, req.DefaultValue) + response.Result = result default: errStr := fmt.Sprintf("unsupported assignment type: %s", req.AssignmentType)