/
response.go
152 lines (133 loc) · 3.51 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package fetcher
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
//ErrMsgLengthLimit max error message length
var ErrMsgLengthLimit = 512
//Response fetch response struct
type Response struct {
*http.Response
bytes *[]byte
}
//BodyContent read and return body content from response.
//Response body will be closed after first read.
func (r *Response) BodyContent() ([]byte, error) {
if r.bytes != nil {
return *r.bytes, nil
}
defer r.Response.Body.Close()
bs, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
r.bytes = &bs
return *r.bytes, nil
}
//Error return response body content as error.
func (r *Response) Error() string {
bs, err := r.BodyContent()
if err != nil {
return err.Error()
}
msg := fmt.Sprintf("fetcher:http error [%s %s ] %s : %s", r.Response.Request.Method, r.Response.Request.URL.String(), r.Status, string(bs))
if len(msg) > ErrMsgLengthLimit {
msg = msg[:ErrMsgLengthLimit]
}
return msg
}
//NewAPICodeErr make a api code error which contains a error code.
func (r *Response) NewAPICodeErr(code interface{}) error {
bs, err := r.BodyContent()
if err != nil {
return err
}
return NewAPICodeErr(r.Response.Request.URL.String(), r.Response.Request.Method, code, bs)
}
//NewResponse create new response
func NewResponse() *Response {
return &Response{}
}
//ConvertResponse convert http response to fetch response
func ConvertResponse(resp *http.Response) *Response {
r := NewResponse()
r.Response = resp
return r
}
//NewAPICodeErr create a new api code error with given url,method,code,and content.
func NewAPICodeErr(url string, method string, code interface{}, content []byte) *APICodeErr {
return &APICodeErr{
URI: url,
Method: method,
Code: fmt.Sprint(code),
Content: content,
}
}
//APICodeErr api code error struct.
type APICodeErr struct {
//URI api uri.
URI string
//Code api error code.
Code string
//Method request method
Method string
//Content api response.
Content []byte
}
//Error used as a error which return request url,request status,erro code,request content.
//Error max length is ErrMsgLengthLimit.
func (r *APICodeErr) Error() string {
c := string(r.Content)
if len(c) > ErrMsgLengthLimit {
c = c[:ErrMsgLengthLimit]
}
msg := fmt.Sprintf("fetcher:api error [%s %s] code %s : %s", r.URI, r.Method, r.Code, url.PathEscape(c))
if len(msg) > ErrMsgLengthLimit {
msg = msg[:ErrMsgLengthLimit]
}
return msg
}
//ErrorPrivateRef error private ref
func (r *APICodeErr) ErrorPrivateRef() string {
if r.Code == "" {
return ""
}
return fmt.Sprintf("code-%s", r.Code)
}
//GetAPIErrCode get api error code form error.
//Return empty string if err is not an ApiCodeErr
func GetAPIErrCode(err error) string {
r, ok := err.(*APICodeErr)
if ok {
return r.Code
}
return ""
}
//GetAPIErrContent get api error code form error.
//Return empty string if err is not an ApiCodeErr
func GetAPIErrContent(err error) string {
r, ok := err.(*APICodeErr)
if ok {
return string(r.Content)
}
return ""
}
//CompareAPIErrCode check if error is an ApiCodeErr with given api err code.
func CompareAPIErrCode(err error, code interface{}) bool {
return GetAPIErrCode(err) == fmt.Sprint(code)
}
//IsResponseErr check if is response error
func IsResponseErr(err error) bool {
_, ok := err.(*Response)
return ok
}
//CompareResponseErrStatusCode check if error is a ResponseErr with given status code.
func CompareResponseErrStatusCode(err error, statuscode int) bool {
resp, ok := err.(*Response)
if !ok {
return false
}
return resp.StatusCode == statuscode
}