From 0dbd910173528aece944fc09f8616dd0d641d9d9 Mon Sep 17 00:00:00 2001 From: Roman Dmytrenko Date: Sat, 25 Oct 2025 17:32:05 +0100 Subject: [PATCH] feat(flipt): add WithHTTPClient option for custom HTTP client configuration Add WithHTTPClient option to both provider and transport layers to allow users to configure custom HTTP clients. This enables use cases like custom timeouts, proxies, or other HTTP client customizations. The option defaults to http.DefaultClient when not specified. Signed-off-by: Roman Dmytrenko --- providers/flipt/go.sum | 6 ------ providers/flipt/pkg/provider/provider.go | 16 +++++++++++++++- providers/flipt/pkg/provider/provider_test.go | 7 +++++++ providers/flipt/pkg/service/transport/service.go | 14 +++++++++++++- .../flipt/pkg/service/transport/service_test.go | 7 +++++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/providers/flipt/go.sum b/providers/flipt/go.sum index 1775b5b66..df7370e5a 100644 --- a/providers/flipt/go.sum +++ b/providers/flipt/go.sum @@ -19,8 +19,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/open-feature/go-sdk v1.15.1 h1:TC3FtHtOKlGlIbSf3SEpxXVhgTd/bCbuc39XHIyltkw= -github.com/open-feature/go-sdk v1.15.1/go.mod h1:2WAFYzt8rLYavcubpCoiym3iSCXiHdPB6DxtMkv2wyo= github.com/open-feature/go-sdk v1.16.0 h1:5NCHYv5slvNBIZhYXAzAufo0OI59OACZ5tczVqSE+Tg= github.com/open-feature/go-sdk v1.16.0/go.mod h1:EIF40QcoYT1VbQkMPy2ZJH4kvZeY+qGUXAorzSWgKSo= github.com/open-feature/go-sdk v1.17.0 h1:/OUBBw5d9D61JaNZZxb2Nnr5/EJrEpjtKCTY3rspJQk= @@ -55,16 +53,12 @@ go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCt go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= diff --git a/providers/flipt/pkg/provider/provider.go b/providers/flipt/pkg/provider/provider.go index 4db3b24b9..3a62aac01 100644 --- a/providers/flipt/pkg/provider/provider.go +++ b/providers/flipt/pkg/provider/provider.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net/http" "strconv" "github.com/open-feature/go-sdk-contrib/providers/flipt/pkg/service/transport" @@ -25,11 +26,19 @@ type Config struct { TokenProvider sdk.ClientTokenProvider Namespace string GRPCDialOptions []grpc.DialOption + httpClient *http.Client } // Option is a configuration option for the provider. type Option func(*Provider) +// WithHTTPClient returns an [Option] that specifies the HTTP client to use as the basis of communications. +func WithHTTPClient(client *http.Client) Option { + return func(p *Provider) { + p.config.httpClient = client + } +} + // WithAddress sets the address for the remote Flipt gRPC or HTTP API. func WithAddress(address string) Option { return func(p *Provider) { @@ -86,6 +95,7 @@ func NewProvider(opts ...Option) *Provider { Address: "http://localhost:8080", Namespace: "default", GRPCDialOptions: []grpc.DialOption{}, + httpClient: transport.DefaultClient, }} for _, opt := range opts { @@ -93,7 +103,11 @@ func NewProvider(opts ...Option) *Provider { } if p.svc == nil { - topts := []transport.Option{transport.WithAddress(p.config.Address), transport.WithCertificatePath(p.config.CertificatePath)} + topts := []transport.Option{ + transport.WithAddress(p.config.Address), + transport.WithHTTPClient(p.config.httpClient), + transport.WithCertificatePath(p.config.CertificatePath), + } if p.config.TokenProvider != nil { topts = append(topts, transport.WithClientTokenProvider(p.config.TokenProvider)) } diff --git a/providers/flipt/pkg/provider/provider_test.go b/providers/flipt/pkg/provider/provider_test.go index 6dfaf1ddd..b64751c81 100644 --- a/providers/flipt/pkg/provider/provider_test.go +++ b/providers/flipt/pkg/provider/provider_test.go @@ -3,6 +3,7 @@ package flipt import ( "encoding/json" "errors" + "net/http" "testing" of "github.com/open-feature/go-sdk/openfeature" @@ -672,3 +673,9 @@ func TestObjectEvaluation(t *testing.T) { }) } } + +func TestWithHTTPClientOption(t *testing.T) { + client := &http.Client{} + p := NewProvider(WithHTTPClient(client)) + assert.Equal(t, client, p.config.httpClient) +} diff --git a/providers/flipt/pkg/service/transport/service.go b/providers/flipt/pkg/service/transport/service.go index 3dacf7d70..e72593ea3 100644 --- a/providers/flipt/pkg/service/transport/service.go +++ b/providers/flipt/pkg/service/transport/service.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "errors" "fmt" + "net/http" "net/url" "os" "strings" @@ -31,6 +32,8 @@ const ( defaultAddr = "http://localhost:8080" ) +var DefaultClient = &http.Client{Transport: http.DefaultTransport} + // Service is a Transport service. type Service struct { client offlipt.Client @@ -40,11 +43,19 @@ type Service struct { once sync.Once tokenProvider sdk.ClientTokenProvider grpcDialOptions []grpc.DialOption + httpClient *http.Client } // Option is a service option. type Option func(*Service) +// WithHTTPClient returns an [Option] that specifies the HTTP client to use as the basis of communications. +func WithHTTPClient(client *http.Client) Option { + return func(s *Service) { + s.httpClient = client + } +} + // WithAddress sets the address for the remote Flipt gRPC API. func WithAddress(address string) Option { return func(s *Service) { @@ -91,6 +102,7 @@ func New(opts ...Option) *Service { grpcDialOptions: []grpc.DialOption{ grpc.WithStatsHandler(otelgrpc.NewClientHandler()), }, + httpClient: DefaultClient, } for _, opt := range opts { @@ -158,7 +170,7 @@ func (s *Service) instance() (offlipt.Client, error) { opts = append(opts, sdk.WithClientTokenProvider(s.tokenProvider)) } - hclient := sdk.New(sdkhttp.NewTransport(s.address), opts...) + hclient := sdk.New(sdkhttp.NewTransport(s.address, sdkhttp.WithHTTPClient(s.httpClient)), opts...) if u.Scheme == "https" || u.Scheme == "http" { s.client = &fclient{ hclient.Flipt(), diff --git a/providers/flipt/pkg/service/transport/service_test.go b/providers/flipt/pkg/service/transport/service_test.go index c73332ec3..656769d04 100644 --- a/providers/flipt/pkg/service/transport/service_test.go +++ b/providers/flipt/pkg/service/transport/service_test.go @@ -1,6 +1,7 @@ package transport import ( + "net/http" "testing" of "github.com/open-feature/go-sdk/openfeature" @@ -288,3 +289,9 @@ func TestGRPCToOpenFeatureError(t *testing.T) { }) } } + +func TestWithHTTPClientOption(t *testing.T) { + client := &http.Client{} + p := New(WithHTTPClient(client)) + assert.Equal(t, client, p.httpClient) +}