github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/resty/response.go (about) 1 // Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved. 2 // resty source code and usage is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package resty 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "strings" 13 "time" 14 ) 15 16 //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 17 // Response struct and methods 18 //_______________________________________________________________________ 19 20 // Response struct holds response values of executed request. 21 type Response struct { 22 Request *Request 23 RawResponse *http.Response 24 25 body []byte 26 size int64 27 receivedAt time.Time 28 } 29 30 // Body method returns HTTP response as []byte array for the executed request. 31 // 32 // Note: `Response.Body` might be nil, if `Request.SetOutput` is used. 33 func (r *Response) Body() []byte { 34 if r.RawResponse == nil { 35 return []byte{} 36 } 37 return r.body 38 } 39 40 // Status method returns the HTTP status string for the executed request. 41 // 42 // Example: 200 OK 43 func (r *Response) Status() string { 44 if r.RawResponse == nil { 45 return "" 46 } 47 return r.RawResponse.Status 48 } 49 50 // StatusCode method returns the HTTP status code for the executed request. 51 // 52 // Example: 200 53 func (r *Response) StatusCode() int { 54 if r.RawResponse == nil { 55 return 0 56 } 57 return r.RawResponse.StatusCode 58 } 59 60 // Proto method returns the HTTP response protocol used for the request. 61 func (r *Response) Proto() string { 62 if r.RawResponse == nil { 63 return "" 64 } 65 return r.RawResponse.Proto 66 } 67 68 // Result method returns the response value as an object if it has one 69 func (r *Response) Result() interface{} { return r.Request.Result } 70 71 // Error method returns the error object if it has one 72 func (r *Response) Error() interface{} { return r.Request.Error } 73 74 // Header method returns the response headers 75 func (r *Response) Header() http.Header { 76 if r.RawResponse == nil { 77 return http.Header{} 78 } 79 return r.RawResponse.Header 80 } 81 82 // Cookies method to access all the response cookies 83 func (r *Response) Cookies() []*http.Cookie { 84 if r.RawResponse == nil { 85 return make([]*http.Cookie, 0) 86 } 87 return r.RawResponse.Cookies() 88 } 89 90 // String method returns the body of the server response as String. 91 func (r *Response) String() string { 92 if r.body == nil { 93 return "" 94 } 95 return strings.TrimSpace(string(r.body)) 96 } 97 98 // Time method returns the time of HTTP response time that from request we sent and received a request. 99 // 100 // See `Response.ReceivedAt` to know when client received response and see `Response.Request.Time` to know 101 // when client sent a request. 102 func (r *Response) Time() time.Duration { 103 if r.Request.clientTrace != nil { 104 return r.Request.TraceInfo().TotalTime 105 } 106 return r.receivedAt.Sub(r.Request.Time) 107 } 108 109 // ReceivedAt method returns when response got received from server for the request. 110 func (r *Response) ReceivedAt() time.Time { return r.receivedAt } 111 112 // Size method returns the HTTP response size in bytes. Ya, you can relay on HTTP `Content-Length` header, 113 // however it won't be good for chucked transfer/compressed response. Since Resty calculates response size 114 // at the client end. You will get actual size of the http response. 115 func (r *Response) Size() int64 { return r.size } 116 117 // RawBody method exposes the HTTP raw response body. Use this method in-conjunction with `SetDoNotParseResponse` 118 // option otherwise you get an error as `read err: http: read on closed response body`. 119 // 120 // Do not forget to close the body, otherwise you might get into connection leaks, no connection reuse. 121 // Basically you have taken over the control of response parsing from `Resty`. 122 func (r *Response) RawBody() io.ReadCloser { 123 if r.RawResponse == nil { 124 return nil 125 } 126 return r.RawResponse.Body 127 } 128 129 // IsSuccess method returns true if HTTP status `code >= 200 and <= 299` otherwise false. 130 func (r *Response) IsSuccess() bool { return r.StatusCode() > 199 && r.StatusCode() < 300 } 131 132 // IsError method returns true if HTTP status `code >= 400` otherwise false. 133 func (r *Response) IsError() bool { return r.StatusCode() > 399 } 134 135 //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 136 // Response Unexported methods 137 //_______________________________________________________________________ 138 139 func (r *Response) setReceivedAt() { 140 r.receivedAt = time.Now() 141 if r.Request.clientTrace != nil { 142 r.Request.clientTrace.endTime = r.receivedAt 143 } 144 } 145 146 func (r *Response) fmtBodyString(sl int64) string { 147 if r.body != nil { 148 if int64(len(r.body)) > sl { 149 return fmt.Sprintf("***** RESPONSE TOO LARGE (size - %d) *****", len(r.body)) 150 } 151 ct := r.Header().Get(hdrContentTypeKey) 152 if IsJSONType(ct) { 153 out := acquireBuffer() 154 defer releaseBuffer(out) 155 err := json.Indent(out, r.body, "", " ") 156 if err != nil { 157 return fmt.Sprintf("*** Error: Unable to format response body - \"%s\" ***\n\nLog Body as-is:\n%s", err, r.String()) 158 } 159 return out.String() 160 } 161 return r.String() 162 } 163 164 return "***** NO CONTENT *****" 165 }