diff --git a/client/client.go b/client/client.go index c4cb08d..cfd8ed5 100644 --- a/client/client.go +++ b/client/client.go @@ -217,3 +217,27 @@ func NewClient(opts ...Option) *Client { } return c } + +// WithHTTPClient swaps in a caller-supplied *http.Client. Use this +// when the application has its own connection pool, mTLS config, or +// auth-injecting transport that other Options like WithTimeout can't +// express. The supplied client's Timeout, Jar, and Transport are +// preserved as-is. +func WithHTTPClient(h *http.Client) Option { + return func(c *Client) { + c.HTTPClient = h + } +} + +// WithTransport replaces the underlying http.RoundTripper without +// touching the Client's other settings (timeout, jar, etc.). Useful +// for wrapping the transport in middleware (auth, logging, retry, +// rate-limit) while keeping the rest of the configured shape intact. +func WithTransport(rt http.RoundTripper) Option { + return func(c *Client) { + if c.HTTPClient == nil { + c.HTTPClient = &http.Client{Timeout: defaultTimeout} + } + c.HTTPClient.Transport = rt + } +} diff --git a/client/options_test.go b/client/options_test.go new file mode 100644 index 0000000..32af915 --- /dev/null +++ b/client/options_test.go @@ -0,0 +1,49 @@ +package client + +import ( + "net/http" + "testing" + "time" +) + +func TestWithHTTPClient(t *testing.T) { + custom := &http.Client{Timeout: 7 * time.Second} + c := NewClient(WithHTTPClient(custom)) + if c.HTTPClient != custom { + t.Errorf("HTTPClient = %p, want %p", c.HTTPClient, custom) + } + if c.HTTPClient.Timeout != 7*time.Second { + t.Errorf("supplied Timeout not preserved: got %v", c.HTTPClient.Timeout) + } +} + +type stubTransport struct{ called bool } + +func (s *stubTransport) RoundTrip(_ *http.Request) (*http.Response, error) { + s.called = true + return nil, http.ErrServerClosed +} + +func TestWithTransport(t *testing.T) { + rt := &stubTransport{} + c := NewClient(WithTransport(rt)) + if c.HTTPClient.Transport != rt { + t.Errorf("Transport not set; got %v", c.HTTPClient.Transport) + } + // Other Client defaults should remain. + if c.HTTPClient.Timeout == 0 { + t.Error("WithTransport should preserve default timeout") + } +} + +// WithTransport over a Client whose HTTPClient was nilled out (via an +// earlier custom option) should still attach without panicking. +func TestWithTransport_NilHTTPClient(t *testing.T) { + c := DefaultClient() + c.HTTPClient = nil + rt := &stubTransport{} + WithTransport(rt)(c) + if c.HTTPClient == nil || c.HTTPClient.Transport != rt { + t.Errorf("WithTransport should backfill HTTPClient; got %+v", c.HTTPClient) + } +}