Skip to content

Commit

Permalink
Update to support prehooks and posthooks
Browse files Browse the repository at this point in the history
  • Loading branch information
darylnwk committed Apr 29, 2020
1 parent 1a7c8ff commit 838e144
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 12 deletions.
36 changes: 24 additions & 12 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ const (

// Client defines a HTTP client
type Client struct {
Client *http.Client
Retryer retry.Retryer
Client *http.Client
Retryer retry.Retryer
Prehooks []Prehook
Posthooks []Posthook
}

// NewClient initialises a new `Client`
Expand All @@ -28,6 +30,8 @@ func NewClient(opts ...Option) *Client {
Retryer: retry.Retryer{
Attempts: defaultRetryAttempts,
},
Prehooks: []Prehook{},
Posthooks: []Posthook{},
}

for _, opt := range opts {
Expand All @@ -41,20 +45,28 @@ func NewClient(opts ...Option) *Client {
func (client *Client) Do(request *http.Request) (*http.Response, error) {
var (
response *http.Response
)

success, errs := client.Retryer.Do(func() error {
var err error
success, errs = client.Retryer.Do(func() error {
var err error

for _, prehook := range client.Prehooks {
prehook(request)
}

response, err = client.Client.Do(request)
response, err = client.Client.Do(request)

// Retry only on 5xx status codes
if response != nil && response.StatusCode >= http.StatusInternalServerError {
return fmt.Errorf("retrying on %s", response.Status)
}
for _, posthook := range client.Posthooks {
posthook(response, err)
}

return err
})
// Retry only on 5xx status codes
if response != nil && response.StatusCode >= http.StatusInternalServerError {
return fmt.Errorf("retrying on %s", response.Status)
}

return err
})
)

if !success {
return response, fmt.Errorf("httpclient: request occurred with errors: %s", errs)
Expand Down
23 changes: 23 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,26 @@ func TestClient_DoWithInternalServerError(t *testing.T) {
assert.EqualError(t, err, "httpclient: request occurred with errors: retrying on 500 Internal Server Error; retrying on 500 Internal Server Error")
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
}

func TestClient_DoWithHook(t *testing.T) {
var (
url = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})).URL
client = httpclient.NewClient(
httpclient.OptionAttempts(2),
httpclient.OptionAddPrehook(func(req *http.Request) {
assert.Equal(t, url, req.URL.String())
}),
httpclient.OptionAddPosthook(func(resp *http.Response, err error) {
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}),
)
request, _ = http.NewRequest(http.MethodPost, url, strings.NewReader(`{"foo": "bar"}`))
response, err = client.Do(request)
)

assert.NoError(t, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
}
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
Expand Down
14 changes: 14 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,17 @@ func OptionJitter(fn func(backoff time.Duration) time.Duration) Option {
client.Retryer.Jitter = fn
}
}

// OptionAddPrehook adds a prehook to `Client`
func OptionAddPrehook(prehook func(request *http.Request)) Option {
return func(client *Client) {
client.Prehooks = append(client.Prehooks, prehook)
}
}

// OptionAddPosthook adds a posthook to `Client`
func OptionAddPosthook(posthook func(response *http.Response, err error)) Option {
return func(client *Client) {
client.Posthooks = append(client.Posthooks, posthook)
}
}
6 changes: 6 additions & 0 deletions posthook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package httpclient

import "net/http"

// Posthook defines a hook called after a HTTP request
type Posthook func(response *http.Response, err error)
6 changes: 6 additions & 0 deletions prehook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package httpclient

import "net/http"

// Prehook defines a hook called before a HTTP request
type Prehook func(request *http.Request)

0 comments on commit 838e144

Please sign in to comment.