internal/requesthelper/request.go (50 lines of code) (raw):
package requesthelper
import (
"fmt"
"net"
"net/http"
"time"
"github.com/go-kit/kit/log"
)
// RequestFactory describes a method to create HTTP requests.
type RequestFactory interface {
// GetRequest returns a new GET request for the resource.
GetRequest(ctx *log.Context, eTag string) (*http.Request, error)
}
// RequestManager provides an abstraction for http requests
type RequestManager struct {
httpClient *http.Client
requestFactory RequestFactory
}
// GetRequestManager returns a request manager for json requests
func GetRequestManager(rf RequestFactory, timeout time.Duration) *RequestManager {
return &RequestManager{
httpClient: getHTTPClient(timeout),
requestFactory: rf,
}
}
// MakeRequest retrieves a response body and checks the response status code to see
// if it is 200 OK and then returns the response body. It issues a new request
// every time called. It is caller's responsibility to close the response body.
func (rm *RequestManager) MakeRequest(ctx *log.Context, eTag string) (*http.Response, error) {
req, err := rm.requestFactory.GetRequest(ctx, eTag)
if err != nil {
return nil, err
}
resp, err := rm.httpClient.Do(req)
if err != nil {
return resp, err
}
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusPartialContent {
return resp, nil
}
err = fmt.Errorf("unexpected status code: actual=%d expected=%d", resp.StatusCode, http.StatusOK)
return resp, err
}
// httpClient is the default client to be used. http.Get() uses a client without timeouts (http.DefaultClient)
// However, an infinite timeout will cause the deployment to fail so here we are setting a specific timeout.
func getHTTPClient(timeout time.Duration) *http.Client {
return &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: timeout,
KeepAlive: 30 * time.Second,
}).Dial,
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 10 * time.Second,
ResponseHeaderTimeout: 20 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
Timeout: timeout}
}