Skip to content

Commit 058f837

Browse files
erkasahidvelji
andauthored
feat(ofrep): add header, base URI, and timeout options (#794)
Signed-off-by: Roman Dmytrenko <[email protected]> Co-authored-by: Sahid Velji <[email protected]>
1 parent f74c0c3 commit 058f837

File tree

7 files changed

+83
-21
lines changed

7 files changed

+83
-21
lines changed

providers/ofrep/README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Use OFREP provider with the latest OpenFeature Go SDK
99

1010
```sh
1111
go get github.com/open-feature/go-sdk-contrib/providers/ofrep
12-
go get github.com/open-feature/go-sdk
1312
```
1413

1514
## Usage
@@ -31,14 +30,16 @@ openfeature.SetProvider(ofrepProvider)
3130
You can configure the provider using following configuration options,
3231

3332
| Configuration option | Details |
34-
|----------------------|-------------------------------------------------------------------------------------------------------------------------|
33+
| -------------------- | ----------------------------------------------------------------------------------------------------------------------- |
3534
| WithApiKeyAuth | Set the token to be used with "X-API-Key" header |
3635
| WithBearerToken | Set the token to be used with "Bearer" HTTP Authorization schema |
37-
| WithClient | Provider a custom, pre-configured http.Client for OFREP service communication |
36+
| WithClient | Provide a custom, pre-configured http.Client for OFREP service communication |
3837
| WithHeaderProvider | Register a custom header provider for OFREP calls. You may utilize this for custom authentication/authorization headers |
38+
| WithHeader | Set a custom header to be used for authorization |
39+
| WithBaseURI | Set the base URI of the OFREP service |
40+
| WithTimeout | Set the timeout for the http client used for communication with the OFREP service (ignored if custom client is used) |
3941

40-
41-
For example, consider below example which set bearer token and provider a customized http client,
42+
For example, consider below example which sets bearer token and provides a customized http client,
4243

4344
```go
4445
provider := ofrep.NewProvider(
@@ -47,4 +48,4 @@ provider := ofrep.NewProvider(
4748
ofrep.WithClient(&http.Client{
4849
Timeout: 1 * time.Second,
4950
}))
50-
```
51+
```

providers/ofrep/go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
22
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
3-
github.com/open-feature/go-sdk v1.15.1 h1:TC3FtHtOKlGlIbSf3SEpxXVhgTd/bCbuc39XHIyltkw=
4-
github.com/open-feature/go-sdk v1.15.1/go.mod h1:2WAFYzt8rLYavcubpCoiym3iSCXiHdPB6DxtMkv2wyo=
5-
github.com/open-feature/go-sdk v1.16.0 h1:5NCHYv5slvNBIZhYXAzAufo0OI59OACZ5tczVqSE+Tg=
6-
github.com/open-feature/go-sdk v1.16.0/go.mod h1:EIF40QcoYT1VbQkMPy2ZJH4kvZeY+qGUXAorzSWgKSo=
73
github.com/open-feature/go-sdk v1.17.0 h1:/OUBBw5d9D61JaNZZxb2Nnr5/EJrEpjtKCTY3rspJQk=
84
github.com/open-feature/go-sdk v1.17.0/go.mod h1:lPxPSu1UnZ4E3dCxZi5gV3et2ACi8O8P+zsTGVsDZUw=
9-
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
10-
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
115
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
126
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
13-
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
14-
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
7+
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
8+
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=

providers/ofrep/internal/evaluate/flags_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ func genericValidator[T knownTypes](test testDefinition[T], resolvedValue T, rea
359359
}
360360

361361
if !reflect.DeepEqual(test.defaultValue, resolvedValue) {
362-
t.Errorf("expected deafault value %v, but got %v", test.defaultValue, resolvedValue)
362+
t.Errorf("expected default value %v, but got %v", test.defaultValue, resolvedValue)
363363
}
364364

365365
if reason != of.ErrorReason {

providers/ofrep/internal/evaluate/resolver.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ func NewOutboundResolver(cfg outbound.Configuration) *OutboundResolver {
3131
func (g *OutboundResolver) resolveSingle(ctx context.Context, key string, evalCtx map[string]any) (*successDto, *of.ResolutionError) {
3232
b, err := json.Marshal(requestFrom(evalCtx))
3333
if err != nil {
34-
resErr := of.NewGeneralResolutionError(fmt.Sprintf("context marshelling error: %v", err))
34+
resErr := of.NewGeneralResolutionError(fmt.Sprintf("context marshelling error: %v", err), err)
3535
return nil, &resErr
3636
}
3737

3838
rsp, err := g.client.Single(ctx, key, b)
3939
if err != nil {
40-
resErr := of.NewGeneralResolutionError(fmt.Sprintf("ofrep request error: %v", err))
40+
resErr := of.NewGeneralResolutionError(fmt.Sprintf("ofrep request error: %v", err), err)
4141
return nil, &resErr
4242
}
4343

@@ -47,7 +47,7 @@ func (g *OutboundResolver) resolveSingle(ctx context.Context, key string, evalCt
4747
var success evaluationSuccess
4848
err := json.Unmarshal(rsp.Data, &success)
4949
if err != nil {
50-
resErr := of.NewParseErrorResolutionError(fmt.Sprintf("error parsing the response: %v", err))
50+
resErr := of.NewParseErrorResolutionError(fmt.Sprintf("error parsing the response: %v", err), err)
5151
return nil, &resErr
5252
}
5353
return toSuccessDto(success)
@@ -82,7 +82,7 @@ func parseError400(data []byte) *of.ResolutionError {
8282
var evalError evaluationError
8383
err := json.Unmarshal(data, &evalError)
8484
if err != nil {
85-
resErr := of.NewGeneralResolutionError(fmt.Sprintf("error parsing error payload: %v", err))
85+
resErr := of.NewGeneralResolutionError(fmt.Sprintf("error parsing error payload: %v", err), err)
8686
return &resErr
8787
}
8888

@@ -127,7 +127,7 @@ func parseError500(data []byte) *of.ResolutionError {
127127

128128
err := json.Unmarshal(data, &evalError)
129129
if err != nil {
130-
resErr = of.NewGeneralResolutionError(fmt.Sprintf("error parsing error payload: %v", err))
130+
resErr = of.NewGeneralResolutionError(fmt.Sprintf("error parsing error payload: %v", err), err)
131131
} else {
132132
resErr = of.NewGeneralResolutionError(evalError.ErrorDetails)
133133
}

providers/ofrep/internal/outbound/http.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type Configuration struct {
2121
BaseURI string
2222
Callbacks []HeaderCallback
2323
Client *http.Client
24+
Timeout time.Duration
2425
}
2526

2627
type Resolution struct {
@@ -39,7 +40,7 @@ type Outbound struct {
3940
func NewHttp(cfg Configuration) *Outbound {
4041
if cfg.Client == nil {
4142
cfg.Client = &http.Client{
42-
Timeout: 10 * time.Second,
43+
Timeout: cfg.Timeout,
4344
}
4445
}
4546

@@ -62,6 +63,8 @@ func (h *Outbound) Single(ctx context.Context, key string, payload []byte) (*Res
6263
return nil, &resErr
6364
}
6465

66+
req.Header.Set("Content-Type", "application/json")
67+
6568
for _, callback := range h.headerProvider {
6669
req.Header.Set(callback())
6770
}

providers/ofrep/provider.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7+
"time"
78

89
"github.com/open-feature/go-sdk-contrib/providers/ofrep/internal/evaluate"
910
"github.com/open-feature/go-sdk-contrib/providers/ofrep/internal/outbound"
1011
"github.com/open-feature/go-sdk/openfeature"
1112
)
1213

14+
var _ openfeature.FeatureProvider = &Provider{}
15+
1316
// Provider implementation for OFREP
1417
type Provider struct {
1518
evaluator Evaluator
@@ -22,6 +25,7 @@ type Option func(*outbound.Configuration)
2225
func NewProvider(baseUri string, options ...Option) *Provider {
2326
cfg := outbound.Configuration{
2427
BaseURI: baseUri,
28+
Timeout: 10 * time.Second,
2529
}
2630

2731
for _, option := range options {
@@ -98,3 +102,27 @@ func WithClient(client *http.Client) func(configuration *outbound.Configuration)
98102
configuration.Client = client
99103
}
100104
}
105+
106+
// WithHeader allows to set a custom header
107+
func WithHeader(key, value string) func(*outbound.Configuration) {
108+
return func(c *outbound.Configuration) {
109+
c.Callbacks = append(c.Callbacks, func() (string, string) {
110+
return key, value
111+
})
112+
}
113+
}
114+
115+
// WithBaseURI allows to override the base URI of the OFREP service
116+
func WithBaseURI(baseURI string) func(*outbound.Configuration) {
117+
return func(c *outbound.Configuration) {
118+
c.BaseURI = baseURI
119+
}
120+
}
121+
122+
// WithTimeout allows to configure the timeout for the http client used for communication with the OFREP service.
123+
// This option is ignored if a custom client is provided via WithClient.
124+
func WithTimeout(timeout time.Duration) func(*outbound.Configuration) {
125+
return func(c *outbound.Configuration) {
126+
c.Timeout = timeout
127+
}
128+
}

providers/ofrep/provider_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,42 @@ func TestConfigurations(t *testing.T) {
6262
t.Errorf("expected value %s, but got %s", "TOKEN", v)
6363
}
6464
})
65+
66+
t.Run("validate custom header", func(t *testing.T) {
67+
c := outbound.Configuration{}
68+
69+
WithHeader("X-Custom-Header", "CustomValue")(&c)
70+
71+
h, v := c.Callbacks[0]()
72+
73+
if h != "X-Custom-Header" {
74+
t.Errorf("expected header %s, but got %s", "X-Custom-Header", h)
75+
}
76+
77+
if v != "CustomValue" {
78+
t.Errorf("expected value %s, but got %s", "CustomValue", v)
79+
}
80+
})
81+
82+
t.Run("validate base URI override", func(t *testing.T) {
83+
c := outbound.Configuration{BaseURI: "http://initial.example.com"}
84+
85+
WithBaseURI("http://override.example.com")(&c)
86+
87+
if c.BaseURI != "http://override.example.com" {
88+
t.Errorf("expected BaseURI %s, but got %s", "http://override.example.com", c.BaseURI)
89+
}
90+
})
91+
92+
t.Run("validate timeout configuration", func(t *testing.T) {
93+
c := outbound.Configuration{}
94+
95+
WithTimeout(5 * time.Second)(&c)
96+
97+
if c.Timeout != 5*time.Second {
98+
t.Errorf("expected Timeout %v, but got %v", 5*time.Second, c.Timeout)
99+
}
100+
})
65101
}
66102

67103
func TestWiringE2E(t *testing.T) {

0 commit comments

Comments
 (0)