From b04385a7c3839ccd651f7d58eda13326b3d3333b Mon Sep 17 00:00:00 2001 From: Ravi Shekhar Jethani Date: Mon, 3 Jul 2023 03:40:13 +0200 Subject: [PATCH] Separate response decoders for success and failure 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! --- sling.go | 65 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/sling.go b/sling.go index cb82f2b..10e252f 100644 --- a/sling.go +++ b/sling.go @@ -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{}, } } @@ -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, } } @@ -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 } @@ -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 } @@ -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