Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .harness/ffgolangserversdk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pipeline:
identifier: Build_and_Test
spec:
connectorRef: DockerHub
image: golang:1.19.9
image: golang:1.20.0
shell: Sh
command: |-
go install github.com/jstemmer/go-junit-report@latest
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $(GOPATH)/bin/gosec:

$(GOPATH)/bin/oapi-codegen:
@echo "🔘 Installing oapicodegen ... (`date '+%H:%M:%S'`)"
@go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.11.0
@go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0

PHONY+= tools
tools: $(GOPATH)/bin/golangci-lint $(GOPATH)/bin/golint $(GOPATH)/bin/gosec $(GOPATH)/bin/goimports $(GOPATH)/bin/oapi-codegen
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ For a sample FF Golang SDK project, see our [test Golang project](examples/getti
![FeatureFlags](./docs/images/ff-gui.png)

## Requirements
[Golang 1.6](https://go.dev/doc/install) or newer (go version)<br>

- Starting with SDK version v0.1.21, Golang version 1.20 or later is required.
- Earlier versions of the SDK require Golang versions newer than 1.6 but older than 1.19.
- For installation details, please refer to [Golang's official installation guide](https://go.dev/doc/install).
## Quickstart
To follow along with our test code sample, make sure you’ve:

Expand Down
2 changes: 1 addition & 1 deletion analyticsservice/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func (as *AnalyticsService) sendDataAndResetCache(ctx context.Context) {
}
as.logger.Debug(string(jsonData))

resp, err := mClient.PostMetricsWithResponse(ctx, metricsclient.EnvironmentPathParam(as.environmentID), analyticsPayload)
resp, err := mClient.PostMetricsWithResponse(ctx, metricsclient.EnvironmentPathParam(as.environmentID), nil, analyticsPayload)
if err != nil {
as.logger.Warn(err)
return
Expand Down
84 changes: 51 additions & 33 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/harness/ff-golang-server-sdk/analyticsservice"
"github.com/harness/ff-golang-server-sdk/metricsclient"

"github.com/deepmap/oapi-codegen/pkg/securityprovider"
"github.com/deepmap/oapi-codegen/v2/pkg/securityprovider"
"github.com/golang-jwt/jwt"
"github.com/harness/ff-golang-server-sdk/rest"
"github.com/harness/ff-golang-server-sdk/stream"
Expand Down Expand Up @@ -333,30 +333,9 @@ func (c *CfClient) authenticate(ctx context.Context) error {
return err
}

responseError := findErrorInResponse(response)

// Indicate that we should retry
if responseError != nil && responseError.Code == "500" {
return RetryableAuthError{
StatusCode: responseError.Code,
Message: responseError.Message,
}
}

// Indicate that we shouldn't retry on non-500 errors
if responseError != nil {
return NonRetryableAuthError{
StatusCode: responseError.Code,
Message: responseError.Message,
}
}

// Defensive check to handle the case that all responses are nil
if response.JSON200 == nil {
return RetryableAuthError{
StatusCode: "No error status code returned from server",
Message: "No error message returned from server ",
}
// Use processAuthResponse to handle any errors based on the HTTP response
if processedError := processAuthResponse(response); processedError != nil {
return processedError
}

c.token = response.JSON200.AuthToken
Expand Down Expand Up @@ -554,7 +533,7 @@ func (c *CfClient) retrieveFlags(ctx context.Context) error {
c.mux.RLock()
defer c.mux.RUnlock()
c.config.Logger.Info("Retrieving flags started")
flags, err := c.api.GetFeatureConfigWithResponse(ctx, c.environmentID)
flags, err := c.api.GetFeatureConfigWithResponse(ctx, c.environmentID, nil)
if err != nil {
// log
return err
Expand All @@ -579,7 +558,7 @@ func (c *CfClient) retrieveSegments(ctx context.Context) error {
c.mux.RLock()
defer c.mux.RUnlock()
c.config.Logger.Info("Retrieving segments started")
segments, err := c.api.GetAllSegmentsWithResponse(ctx, c.environmentID)
segments, err := c.api.GetAllSegmentsWithResponse(ctx, c.environmentID, nil)
if err != nil {
// log
return err
Expand Down Expand Up @@ -769,13 +748,52 @@ func getLogger(options ...ConfigOption) logger.Logger {
return dummyConfig.Logger
}

// findErrorInResponse parses an auth response and returns the response error if it exists
func findErrorInResponse(resp *rest.AuthenticateResponse) *rest.Error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The types have changed here, presumably because of the v2 tool

responseErrors := []*rest.Error{resp.JSON401, resp.JSON403, resp.JSON404, resp.JSON500}
for _, responseError := range responseErrors {
if responseError != nil {
return responseError
// processAuthResponse checks the authentication response for errors and categorizes them as retryable or non-retryable.
func processAuthResponse(response *rest.AuthenticateResponse) error {
if response == nil {
return RetryableAuthError{
StatusCode: "No error status code returned from server",
Message: "No error message returned from server ",
}
}

if response.JSON200 != nil {
return nil
}

// Handle retryable error
if response.JSON500 != nil {
return RetryableAuthError{
StatusCode: response.JSON500.Code,
Message: response.JSON500.Message,
}
}

// Handle non-retryable errors.
var nonRetryableError *rest.Error
switch {
case response.JSON401 != nil:
nonRetryableError = &rest.Error{Code: response.JSON401.Code, Message: response.JSON401.Message}
case response.JSON403 != nil:
nonRetryableError = &rest.Error{Code: response.JSON403.Code, Message: response.JSON403.Message}
case response.JSON404 != nil:
nonRetryableError = &rest.Error{Code: response.JSON404.Code, Message: response.JSON404.Message}
}

if nonRetryableError != nil {
return NonRetryableAuthError{
StatusCode: nonRetryableError.Code,
Message: nonRetryableError.Message,
}
}

// Defensive check to handle the case that all responses are nil
if response.JSON200 == nil {
return RetryableAuthError{
StatusCode: "No error status code returned from server",
Message: "No error message returned from server ",
}
}

return nil
}
4 changes: 2 additions & 2 deletions evaluation/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ func (e Evaluator) evaluateVariationMap(variationsMap []rest.VariationMap, targe
for _, variationMap := range variationsMap {
if variationMap.Targets != nil {
for _, t := range *variationMap.Targets {
if *t.Identifier != "" && *t.Identifier == target.Identifier {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again types have changed. Now a string instead of *String

e.logger.Debugf("Specific targeting matched in Variation Map: Variation Map (%v) Target(%v), Variation returned (%s)", *t.Identifier, target, variationMap.Variation)
if t.Identifier != "" && t.Identifier == target.Identifier {
e.logger.Debugf("Specific targeting matched in Variation Map: Variation Map (%v) Target(%v), Variation returned (%s)", t.Identifier, target, variationMap.Variation)
return variationMap.Variation
}
}
Expand Down
4 changes: 2 additions & 2 deletions evaluation/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ func TestEvaluator_evaluateVariationMap(t *testing.T) {
Variation: identifierTrue,
Targets: &[]rest.TargetMap{
{
Identifier: &targetIdentifier,
Identifier: targetIdentifier,
},
},
},
Expand Down Expand Up @@ -1074,7 +1074,7 @@ func TestEvaluator_evaluateFlag(t *testing.T) {
Variation: identifierTrue,
Targets: &[]rest.TargetMap{
{
Identifier: &targetIdentifier,
Identifier: targetIdentifier,
},
},
},
Expand Down
23 changes: 13 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
module github.com/harness/ff-golang-server-sdk

go 1.18
go 1.20

require (
github.com/cenkalti/backoff/v4 v4.2.1
github.com/deepmap/oapi-codegen v1.11.0
github.com/getkin/kin-openapi v0.94.0
github.com/deepmap/oapi-codegen/v2 v2.1.0
Copy link
Contributor Author

Choose a reason for hiding this comment

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

v2 has pretty significant benefits, mainly around reduced dependency bundle. See https://www.jvt.me/posts/2023/10/23/oapi-codegen-v2-decrease/

github.com/getkin/kin-openapi v0.124.0
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.3.0
github.com/google/uuid v1.5.0
github.com/harness-community/sse/v3 v3.1.0
github.com/hashicorp/go-retryablehttp v0.7.4
github.com/hashicorp/golang-lru v0.5.4
github.com/jarcoal/httpmock v1.0.8
github.com/json-iterator/go v1.1.12
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.3
github.com/oapi-codegen/runtime v1.1.1
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.16.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
)

require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/swag v0.22.8 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/net v0.19.0 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading