Skip to content

Commit

Permalink
Added option to expose response body without parsing response #87 (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm authored Aug 17, 2017
1 parent 6d8c785 commit eb3bafb
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 7 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ go:
- 1.8
- tip

install:
- go get -v -t ./...
- go get -v golang.org/x/tools/cmd/cover
# install:
# - go get -v -t ./...
# - go get -v golang.org/x/tools/cmd/cover

script:
- go test ./... -coverprofile=coverage.txt -covermode=atomic
Expand Down
24 changes: 22 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type Client struct {
scheme string
proxyURL *url.URL
closeConnection bool
notParseResponse bool
beforeRequest []func(*Client, *Request) error
udBeforeRequest []func(*Client, *Request) error
preReqHook func(*Client, *Request) error
Expand All @@ -109,6 +110,10 @@ type User struct {
Username, Password string
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Client methods
//___________________________________

// SetHostURL method is to set Host URL in the client instance. It will be used with request
// raised from this client with relative URL
// // Setting HTTP address
Expand Down Expand Up @@ -661,18 +666,33 @@ func (c *Client) SetScheme(scheme string) *Client {
return c
}

// SetCloseConnection method sets variable Close in http request struct with the given
// SetCloseConnection method sets variable `Close` in http request struct with the given
// value. More info: https://golang.org/src/net/http/request.go
func (c *Client) SetCloseConnection(close bool) *Client {
c.closeConnection = close
return c
}

// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
// otherwise you might get into connection leaks, no connection reuse.
//
// Please Note: Response middlewares are not applicable, if you use this option. Basically you have
// taken over the control of response parsing from `Resty`.
func (c *Client) SetDoNotParseResponse(parse bool) *Client {
c.notParseResponse = parse
return c
}

// IsProxySet method returns the true if proxy is set on client otherwise false.
func (c *Client) IsProxySet() bool {
return c.proxyURL != nil
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Client Unexported methods
//___________________________________

// executes the given `Request` object and returns response
func (c *Client) execute(req *Request) (*Response, error) {
defer putBuffer(req.bodyBuf)
Expand Down Expand Up @@ -710,7 +730,7 @@ func (c *Client) execute(req *Request) (*Response, error) {
receivedAt: time.Now(),
}

if err != nil {
if err != nil || req.notParseResponse || c.notParseResponse {
return response, err
}

Expand Down
6 changes: 6 additions & 0 deletions default.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ func SetCloseConnection(close bool) *Client {
return DefaultClient.SetCloseConnection(close)
}

// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
// See `Client.SetDoNotParseResponse` for more information.
func SetDoNotParseResponse(parse bool) *Client {
return DefaultClient.SetDoNotParseResponse(parse)
}

// IsProxySet method returns the true if proxy is set on client otherwise false.
// See `Client.IsProxySet` for more information.
func IsProxySet() bool {
Expand Down
11 changes: 11 additions & 0 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,17 @@ func (r *Request) SetSRV(srv *SRVRecord) *Request {
return r
}

// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
// otherwise you might get into connection leaks, no connection reuse.
//
// Please Note: Response middlewares are not applicable, if you use this option. Basically you have
// taken over the control of response parsing from `Resty`.
func (r *Request) SetDoNotParseResponse(parse bool) *Request {
r.notParseResponse = parse
return r
}

//
// HTTP verb method starts here
//
Expand Down
1 change: 1 addition & 0 deletions request16.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Request struct {
isSaveResponse bool
outputFile string
multipartFiles []*File
notParseResponse bool
}

func (r *Request) addContextIfAvailable() {
Expand Down
1 change: 1 addition & 0 deletions request17.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Request struct {
isSaveResponse bool
outputFile string
multipartFiles []*File
notParseResponse bool
ctx context.Context
}

Expand Down
13 changes: 13 additions & 0 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package resty

import (
"encoding/json"
"io"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -106,6 +107,18 @@ func (r *Response) Size() int64 {
return r.size
}

// RawBody method exposes the HTTP raw response body. Use this method in-conjunction with `SetDoNotParseResponse`
// option otherwise you get an error as `read err: http: read on closed response body`.
//
// Do not forget to close the body, otherwise you might get into connection leaks, no connection reuse.
// Basically you have taken over the control of response parsing from `Resty`.
func (r *Response) RawBody() io.ReadCloser {
if r.RawResponse == nil {
return nil
}
return r.RawResponse.Body
}

func (r *Response) fmtBodyString() string {
bodyStr := "***** NO CONTENT *****"
if r.body != nil {
Expand Down
2 changes: 1 addition & 1 deletion resty.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
package resty

// Version # of resty
const Version = "0.13"
const Version = "1.0-dev"
43 changes: 42 additions & 1 deletion resty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,10 @@ func TestSRV(t *testing.T) {

resp, err := r.Get("/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, (resp != nil))
if resp != nil {
assertEqual(t, http.StatusOK, resp.StatusCode())
}
}

func TestSRVInvalidService(t *testing.T) {
Expand Down Expand Up @@ -1152,6 +1155,44 @@ func TestDeprecatedCodeCovergae(t *testing.T) {
assertEqual(t, "testpass", user1.Password)
}

func TestRequestDoNotParseResponse(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()

resp, err := dc().R().
SetDoNotParseResponse(true).
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
Get(ts.URL + "/")

assertError(t, err)

buf := getBuffer()
defer putBuffer(buf)
_, _ = io.Copy(buf, resp.RawBody())

assertEqual(t, "TestGet: text response", buf.String())
_ = resp.RawBody().Close()

// Manually setting RawResponse as nil
resp, err = dc().R().
SetDoNotParseResponse(true).
Get(ts.URL + "/")

assertError(t, err)

resp.RawResponse = nil
assertEqual(t, true, resp.RawBody() == nil)

// just set test part
SetDoNotParseResponse(true)
assertEqual(t, true, DefaultClient.notParseResponse)
SetDoNotParseResponse(false)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Testing Unexported methods
//___________________________________

func getTestDataPath() string {
pwd, _ := os.Getwd()
return pwd + "/test-data"
Expand Down

0 comments on commit eb3bafb

Please sign in to comment.