diff --git a/go.mod b/go.mod index 811962b..d5c3a83 100644 --- a/go.mod +++ b/go.mod @@ -80,5 +80,5 @@ require ( golang.org/x/crypto v0.19.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/text v0.14.0 ) diff --git a/http_client_wrapper.go b/http_client_wrapper.go index e897a94..8368bef 100644 --- a/http_client_wrapper.go +++ b/http_client_wrapper.go @@ -20,6 +20,7 @@ type httpClientWrapper struct { baseURL string headers map[string]string torProxyURL string + retry uint } type HTTPResponseError struct { @@ -31,7 +32,7 @@ func BuildResponseError(statusCode int, err error) error { return HTTPResponseError{StatusCode: statusCode, error: err} } -func NewHTTPClientWrapper(baseURL, torProxyURL string, timeout time.Duration, headers map[string]string, addJSONHeaders bool) (HTTPClientWrapper, error) { +func NewHTTPClientWrapper(baseURL, torProxyURL string, timeout time.Duration, headers map[string]string, addJSONHeaders bool, opts ...HTTPClientWrapperOption) (HTTPClientWrapper, error) { if headers == nil { headers = map[string]string{} } @@ -49,14 +50,37 @@ func NewHTTPClientWrapper(baseURL, torProxyURL string, timeout time.Duration, he } client.Transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)} } + + params := defaultHTTPClientWrapperOptions + for _, opt := range opts { + opt(¶ms) + } + return &httpClientWrapper{ httpClient: client, baseURL: baseURL, headers: headers, torProxyURL: torProxyURL, + retry: params.Retry, }, nil } +type HTTPClientWrapperOptions struct { + Retry uint +} + +var defaultHTTPClientWrapperOptions = HTTPClientWrapperOptions{ + Retry: 5, +} + +type HTTPClientWrapperOption func(*HTTPClientWrapperOptions) + +func WithRetry(retry uint) HTTPClientWrapperOption { + return func(opts *HTTPClientWrapperOptions) { + opts.Retry = retry + } +} + // ExecuteRequest calls an endpoint, optional body and error handling. path is appended to the baseURL, same for json // headers and authorization. If request results in non 2xx response, will always return error with payload body in err message. // response should have defer response.Body.Close() after the error check as it could be nil when err is != nil @@ -89,7 +113,7 @@ func (h httpClientWrapper) ExecuteRequest(path, method string, body []byte) (*ht return errResp } return err - }, retry.Attempts(5), retry.Delay(500*time.Millisecond), retry.MaxDelay(9*time.Second)) + }, retry.Attempts(h.retry), retry.Delay(500*time.Millisecond), retry.MaxDelay(9*time.Second)) if res == nil { return nil, err diff --git a/http_client_wrapper_test.go b/http_client_wrapper_test.go index 911fa22..6510c74 100644 --- a/http_client_wrapper_test.go +++ b/http_client_wrapper_test.go @@ -10,7 +10,9 @@ import ( func Test_httpClientWrapper_ExecuteRequest_failsTooManyRetries(t *testing.T) { const baseURL = "http://test.com" - hcw, _ := NewHTTPClientWrapper(baseURL, "", 1, nil, true) + retryCount := uint(5) + + hcw, _ := NewHTTPClientWrapper(baseURL, "", 1, nil, true, WithRetry(retryCount)) httpmock.Activate() defer httpmock.DeactivateAndReset() path := "/api/vehicle/v2/makes" @@ -19,7 +21,7 @@ func Test_httpClientWrapper_ExecuteRequest_failsTooManyRetries(t *testing.T) { countInfo := httpmock.GetCallCountInfo() c := countInfo["GET "+baseURL+path] - assert.Equal(t, 5, c, "expected five retries") + assert.Equal(t, int(retryCount), c, "expected five retries") assert.Error(t, err, "expected error") assert.ErrorIs(t, err, err.(HTTPResponseError), "expected HTTPResponseError") assert.Equal(t, 503, err.(HTTPResponseError).StatusCode, "expected 409")