Skip to content

Commit 773c56c

Browse files
feat(client): support custom http clients (#80)
1 parent 00dd085 commit 773c56c

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

internal/requestconfig/requestconfig.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ func UseDefaultParam[T any](dst *param.Field[T], src *T) {
192192
}
193193
}
194194

195+
// This interface is primarily used to describe an [*http.Client], but also
196+
// supports custom HTTP implementations.
197+
type HTTPDoer interface {
198+
Do(req *http.Request) (*http.Response, error)
199+
}
200+
195201
// RequestConfig represents all the state related to one request.
196202
//
197203
// Editing the variables inside RequestConfig directly is unstable api. Prefer
@@ -202,6 +208,7 @@ type RequestConfig struct {
202208
Context context.Context
203209
Request *http.Request
204210
BaseURL *url.URL
211+
CustomHTTPDoer HTTPDoer
205212
HTTPClient *http.Client
206213
Middlewares []middleware
207214
APIKey string
@@ -399,6 +406,9 @@ func (cfg *RequestConfig) Execute() (err error) {
399406
}
400407

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

option/requestoption.go

Lines changed: 26 additions & 3 deletions
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)