Skip to content

Commit

Permalink
Separate response decoders for success and failure
Browse files Browse the repository at this point in the history
Now users can have separate decoders for success and failure responses.

Motivation: Most of the time 5XX responses are not JSON but rather plain
text or html returned by an API Gateway in front of web services. The
web services can gurantee JSON content of their own but cannot control
response format when they are down. Hence we need to aware of this fact
and should be able to deal with such a response gracefully.

Using same decoder makes it difficult hence this new change. Enjoy!
  • Loading branch information
rsjethani committed Jul 11, 2023
1 parent bd74a7a commit b04385a
Showing 1 changed file with 41 additions and 24 deletions.
65 changes: 41 additions & 24 deletions sling.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@ type Sling struct {
queryStructs []interface{}
// body provider
bodyProvider BodyProvider
// response decoder
responseDecoder ResponseDecoder
// response decoders
successDecoder ResponseDecoder
failureDecoder ResponseDecoder
}

// New returns a new Sling with an http DefaultClient.
func New() *Sling {
return &Sling{
httpClient: http.DefaultClient,
method: "GET",
header: make(http.Header),
queryStructs: make([]interface{}, 0),
responseDecoder: jsonDecoder{},
httpClient: http.DefaultClient,
method: "GET",
header: make(http.Header),
queryStructs: make([]interface{}, 0),
successDecoder: jsonDecoder{},
failureDecoder: jsonDecoder{},
}
}

Expand All @@ -71,13 +73,14 @@ func (s *Sling) New() *Sling {
headerCopy[k] = v
}
return &Sling{
httpClient: s.httpClient,
method: s.method,
rawURL: s.rawURL,
header: headerCopy,
queryStructs: append([]interface{}{}, s.queryStructs...),
bodyProvider: s.bodyProvider,
responseDecoder: s.responseDecoder,
httpClient: s.httpClient,
method: s.method,
rawURL: s.rawURL,
header: headerCopy,
queryStructs: append([]interface{}{}, s.queryStructs...),
bodyProvider: s.bodyProvider,
successDecoder: s.successDecoder,
failureDecoder: s.failureDecoder,
}
}

Expand Down Expand Up @@ -349,12 +352,26 @@ func addHeaders(req *http.Request, header http.Header) {

// Sending

// ResponseDecoder sets the Sling's response decoder.
func (s *Sling) ResponseDecoder(decoder ResponseDecoder) *Sling {
if decoder == nil {
return s
// ResponseDecoder sets both success anf failure response decoders to dec.
func (s *Sling) ResponseDecoder(dec ResponseDecoder) *Sling {
s.SuccessDecoder(dec)
s.FailureDecoder(dec)
return s
}

// SuccessDecoder sets success response decoder to dec.
func (s *Sling) SuccessDecoder(dec ResponseDecoder) *Sling {
if dec != nil {
s.successDecoder = dec
}
return s
}

// FailureDecoder sets failure response decoder to dec.
func (s *Sling) FailureDecoder(dec ResponseDecoder) *Sling {
if dec != nil {
s.failureDecoder = dec
}
s.responseDecoder = decoder
return s
}

Expand Down Expand Up @@ -415,9 +432,9 @@ func (s *Sling) Do(req *http.Request, successV, failureV interface{}) (*http.Res
return resp, nil
}

// Decode from json
// Decode response
if successV != nil || failureV != nil {
err = decodeResponse(resp, s.responseDecoder, successV, failureV)
err = s.decodeResponse(resp, successV, failureV)
}
return resp, err
}
Expand All @@ -427,14 +444,14 @@ func (s *Sling) Do(req *http.Request, successV, failureV interface{}) (*http.Res
// otherwise. If the successV or failureV argument to decode into is nil,
// decoding is skipped.
// Caller is responsible for closing the resp.Body.
func decodeResponse(resp *http.Response, decoder ResponseDecoder, successV, failureV interface{}) error {
func (s *Sling) decodeResponse(resp *http.Response, successV, failureV interface{}) error {
if code := resp.StatusCode; 200 <= code && code <= 299 {
if successV != nil {
return decoder.Decode(resp, successV)
return s.successDecoder.Decode(resp, successV)
}
} else {
if failureV != nil {
return decoder.Decode(resp, failureV)
return s.failureDecoder.Decode(resp, failureV)
}
}
return nil
Expand Down

0 comments on commit b04385a

Please sign in to comment.