Skip to content

Commit b5a624f

Browse files
feat(client): support custom http clients (#357)
1 parent b2f8539 commit b5a624f

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

Diff for: internal/requestconfig/requestconfig.go

+10
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,12 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa
189189
return &cfg, nil
190190
}
191191

192+
// This interface is primarily used to describe an [*http.Client], but also
193+
// supports custom HTTP implementations.
194+
type HTTPDoer interface {
195+
Do(req *http.Request) (*http.Response, error)
196+
}
197+
192198
// RequestConfig represents all the state related to one request.
193199
//
194200
// Editing the variables inside RequestConfig directly is unstable api. Prefer
@@ -199,6 +205,7 @@ type RequestConfig struct {
199205
Context context.Context
200206
Request *http.Request
201207
BaseURL *url.URL
208+
CustomHTTPDoer HTTPDoer
202209
HTTPClient *http.Client
203210
Middlewares []middleware
204211
APIKey string
@@ -398,6 +405,9 @@ func (cfg *RequestConfig) Execute() (err error) {
398405
}
399406

400407
handler := cfg.HTTPClient.Do
408+
if cfg.CustomHTTPDoer != nil {
409+
handler = cfg.CustomHTTPDoer.Do
410+
}
401411
for i := len(cfg.Middlewares) - 1; i >= 0; i -= 1 {
402412
handler = applyMiddleware(cfg.Middlewares[i], handler)
403413
}

Diff for: option/requestoption.go

+26-3
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,34 @@ func WithBaseURL(base string) RequestOption {
4040
})
4141
}
4242

43-
// WithHTTPClient returns a RequestOption that changes the underlying [http.Client] used to make this
43+
// HTTPClient is primarily used to describe an [*http.Client], but also
44+
// supports custom implementations.
45+
//
46+
// For bespoke implementations, prefer using an [*http.Client] with a
47+
// custom transport. See [http.RoundTripper] for further information.
48+
type HTTPClient interface {
49+
Do(*http.Request) (*http.Response, error)
50+
}
51+
52+
// WithHTTPClient returns a RequestOption that changes the underlying http client used to make this
4453
// request, which by default is [http.DefaultClient].
45-
func WithHTTPClient(client *http.Client) RequestOption {
54+
//
55+
// For custom uses cases, it is recommended to provide an [*http.Client] with a custom
56+
// [http.RoundTripper] as its transport, rather than directly implementing [HTTPClient].
57+
func WithHTTPClient(client HTTPClient) RequestOption {
4658
return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
47-
r.HTTPClient = client
59+
if client == nil {
60+
return fmt.Errorf("requestoption: custom http client cannot be nil")
61+
}
62+
63+
if c, ok := client.(*http.Client); ok {
64+
// Prefer the native client if possible.
65+
r.HTTPClient = c
66+
r.CustomHTTPDoer = nil
67+
} else {
68+
r.CustomHTTPDoer = client
69+
}
70+
4871
return nil
4972
})
5073
}

0 commit comments

Comments
 (0)