Skip to content

Commit

Permalink
[util] update http request lib
Browse files Browse the repository at this point in the history
  • Loading branch information
agungdwiprasetyo committed Oct 28, 2020
1 parent c0214d1 commit a9c54ee
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 102 deletions.
174 changes: 88 additions & 86 deletions candiutils/http_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,117 @@ package candiutils

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"reflect"
"time"

"github.com/afex/hystrix-go/hystrix"
"gopkg.in/eapache/go-resiliency.v1/retrier"
"github.com/gojektech/heimdall"
"github.com/gojektech/heimdall/httpclient"
"pkg.agungdwiprasetyo.com/candi/tracer"
)

type (
// httpRequest struct
httpRequest struct {
retries int

sleepBetweenRetry time.Duration
client *http.Client
}
// Request struct
type Request struct {
client *httpclient.Client
minHTTPErrorCode int
}

// HTTPRequest abstraction
HTTPRequest interface {
Do(breakerName, method, url string, body interface{}, headers map[string]string) ([]byte, error)
}
)
// HTTPRequest interface
type HTTPRequest interface {
Do(context context.Context, method, url string, reqBody []byte, headers map[string]string) ([]byte, error)
}

// NewHTTPRequest function
// httpRequest's Constructor
func NewHTTPRequest(retries int, sleepBetweenRetry time.Duration) HTTPRequest {
var transport http.RoundTripper = &http.Transport{
DisableKeepAlives: true,
// Request's Constructor
// Returns : *Request
func NewHTTPRequest(retries int, sleepBetweenRetry time.Duration, minHTTPErrorCode int) HTTPRequest {
// define a maximum jitter interval
maximumJitterInterval := 5 * time.Millisecond

// create a backoff
backoff := heimdall.NewConstantBackoff(sleepBetweenRetry, maximumJitterInterval)

// create a new retry mechanism with the backoff
retrier := heimdall.NewRetrier(backoff)

// set http timeout
timeout := 10000 * time.Millisecond

// set http client
client := httpclient.NewClient(
httpclient.WithHTTPTimeout(timeout),
httpclient.WithRetrier(retrier),
httpclient.WithRetryCount(retries),
)

if minHTTPErrorCode <= 0 {
minHTTPErrorCode = http.StatusBadRequest
}

client := &http.Client{}
client.Transport = transport
return &httpRequest{
retries: retries,
sleepBetweenRetry: sleepBetweenRetry,
client: client,
return &Request{
client: client,
minHTTPErrorCode: minHTTPErrorCode,
}
}

// Do function, for http client call
func (r *httpRequest) Do(breakerName, method, url string, body interface{}, headers map[string]string) ([]byte, error) {
hystrix.ConfigureCommand(breakerName, hystrix.CommandConfig{
Timeout: int(10 * time.Second),
MaxConcurrentRequests: 10,
ErrorPercentThreshold: 25,
})

output := make(chan []byte, 1)
errors := hystrix.Go(breakerName,
func() error {
return r.retry(output, method, url, body, headers)
},
func(err error) error {
return err
})

select {
case out := <-output:
return out, nil
case err := <-errors:
func (request *Request) Do(ctx context.Context, method, url string, requestBody []byte, headers map[string]string) (respBody []byte, err error) {
// set request http
req, err := http.NewRequest(method, url, bytes.NewBuffer(requestBody))
if err != nil {
return nil, err
}
}

func (r *httpRequest) retry(output chan []byte, method, url string, body interface{}, headers map[string]string) error {
ret := retrier.New(retrier.ConstantBackoff(r.retries, r.sleepBetweenRetry), nil)
attempt := 0
err := ret.Run(func() error {
attempt++
var req *http.Request

if body != nil {
typeInput := reflect.TypeOf(body)
typeReader := reflect.TypeOf((*io.Reader)(nil)).Elem()
if typeInput.Implements(typeReader) {
reader := body.(io.Reader)
req, _ = http.NewRequest(method, url, reader)
} else {
payload, _ := json.Marshal(body)
buf := bytes.NewBuffer(payload)
req, _ = http.NewRequest(method, url, buf)
}
} else {
req, _ = http.NewRequest(method, url, nil)
// set tracer
trace := tracer.StartTrace(ctx, fmt.Sprintf("HTTP Request: %s %s%s", method, req.URL.Host, req.URL.Path))
defer func() {
if err != nil {
trace.SetError(err)
}
trace.Finish()
}()

for key, value := range headers {
req.Header.Set(key, value)
}
// iterate optional data of headers
for key, value := range headers {
req.Header.Set(key, value)
}

resp, err := r.client.Do(req)
if err == nil {
defer resp.Body.Close()
if resp.StatusCode < 499 {
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
output <- responseBody
return nil
}
err = fmt.Errorf("Status was %d", resp.StatusCode)
trace.InjectHTTPHeader(req)
tags := trace.Tags()
tags["http.headers"] = req.Header
tags["http.method"] = req.Method
tags["http.url"] = req.URL.String()
if requestBody != nil {
tags["request.body"] = string(requestBody)
}

// client request
r, err := request.client.Do(req)
if err != nil {
return nil, err
}
// close response body
defer r.Body.Close()

respBody, err = ioutil.ReadAll(r.Body)

tags["response.body"] = string(respBody)
tags["response.code"] = r.StatusCode
tags["response.status"] = r.Status

if r.StatusCode >= request.minHTTPErrorCode {
err = errors.New(r.Status)
var resp map[string]string
json.Unmarshal(respBody, &resp)
if resp["message"] != "" {
err = errors.New(resp["message"])
}
return err
})
return respBody, err
}

return err
return respBody, err
}
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ go 1.12
require (
github.com/DataDog/zstd v1.4.5 // indirect
github.com/Shopify/sarama v1.24.1
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0
github.com/go-playground/validator/v10 v10.3.0
github.com/go-stack/stack v1.8.0 // indirect
github.com/gojektech/heimdall v5.0.2+incompatible
github.com/gojektech/valkyrie v0.0.0-20190210220504-8f62c1e7ba45 // indirect
github.com/golangid/graphql-go v0.0.4
github.com/gomodule/redigo v2.0.0+incompatible
github.com/google/uuid v1.1.1
Expand All @@ -25,7 +26,6 @@ require (
github.com/mattn/go-isatty v0.0.11 // indirect
github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.9.1 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.4.0
github.com/tidwall/pretty v1.0.1 // indirect
github.com/uber/jaeger-client-go v2.25.0+incompatible
Expand All @@ -39,5 +39,4 @@ require (
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 // indirect
google.golang.org/grpc v1.27.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/eapache/go-resiliency.v1 v1.2.0
)
17 changes: 4 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ github.com/Shopify/sarama v1.24.1 h1:svn9vfN3R1Hz21WR2Gj0VW9ehaDGkiOS+VqlIcZOkMI
github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU=
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
Expand Down Expand Up @@ -42,6 +40,10 @@ github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gojektech/heimdall v5.0.2+incompatible h1:mfGLnHNTKN7b1OMTO4ZvL3oT2P13kqTTV7owK7BZDck=
github.com/gojektech/heimdall v5.0.2+incompatible/go.mod h1:8hRIZ3+Kz0r3GAFI9QrUuvZht8ypg5Rs8schCXioLOo=
github.com/gojektech/valkyrie v0.0.0-20190210220504-8f62c1e7ba45 h1:MO2DsGCZz8phRhLnpFvHEQgTH521sVN/6F2GZTbNO3Q=
github.com/gojektech/valkyrie v0.0.0-20190210220504-8f62c1e7ba45/go.mod h1:tDYRk1s5Pms6XJjj5m2PxAzmQvaDU8GqDf1u6x7yxKw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
Expand All @@ -62,8 +64,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-transport-ws v0.0.0-20190611222414-40c048432299 h1:BdXUpuP9yOGKcwD/mhhZ+6EeAmrPrAQA3yeq4YEOHL4=
Expand All @@ -74,8 +74,6 @@ github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03 h1:FUwcHNlEqkqLjL
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
Expand Down Expand Up @@ -114,10 +112,6 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down Expand Up @@ -202,7 +196,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
Expand All @@ -224,8 +217,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/eapache/go-resiliency.v1 v1.2.0 h1:Ga62yQGVh5jQ/k6rDYhn2UsV9evgp2ZmMwXgGu2YcOQ=
gopkg.in/eapache/go-resiliency.v1 v1.2.0/go.mod h1:ufQ2tre3XZoQT9X8nKYgTaqO8DrIudC5V1EOYUwIka0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
Expand Down

0 comments on commit a9c54ee

Please sign in to comment.