-
Notifications
You must be signed in to change notification settings - Fork 1
/
response.go
138 lines (110 loc) · 2.38 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
package patch
import (
"bytes"
"io"
"io/ioutil"
"net/http"
)
// Response represents the response from a request
type Response struct {
*http.Response
}
// BodyBytes returns the body as a byte slice
func (r *Response) BodyBytes() ([]byte, error) {
switch rc := r.Body.(type) {
case *bufCloser:
return rc.Bytes(), nil
default:
defer func() { _ = rc.Close() }()
// Replace the response body with a bufCloser
buf := &bufCloser{}
r.Body = buf
// Use a TeeReader to read the body while
// simultaneously piping it into the buffer
tr := io.TeeReader(rc, buf)
return ioutil.ReadAll(tr)
}
}
// BodyString returns the body as a string
func (r *Response) BodyString() (string, error) {
b, err := r.BodyBytes()
return string(b), err
}
type DecodeHook func(status int) interface{}
func On2xx(v interface{}) DecodeHook {
return func(status int) interface{} {
if status >= 200 && status < 300 {
return v
}
return nil
}
}
func On4xx(v interface{}) DecodeHook {
return func(status int) interface{} {
if status >= 400 && status < 500 {
return v
}
return nil
}
}
func On5xx(v interface{}) DecodeHook {
return func(status int) interface{} {
if status >= 500 && status < 600 {
return v
}
return nil
}
}
func OnNon2xx(v interface{}) DecodeHook {
return func(status int) interface{} {
if status >= 200 && status < 300 {
return nil
}
return v
}
}
func OnStatus(status int, v interface{}) DecodeHook {
return func(s int) interface{} {
if status == s {
return v
}
return nil
}
}
func (r *Response) Decode(targets ...interface{}) error {
dec, err := inferDecoder(r.Header.Get("Content-Type"))
if err != nil {
return err
}
return r.DecodeUsing(dec, targets...)
}
func (r *Response) DecodeJSON(targets ...interface{}) error {
return r.DecodeUsing(jsonDecoder, targets...)
}
// DecodeUsing decodes the response into the receivers using the given Decoder
func (r *Response) DecodeUsing(dec Decoder, targets ...interface{}) error {
body, err := r.BodyBytes()
if err != nil {
return err
}
for _, receiver := range targets {
switch v := receiver.(type) {
case DecodeHook:
receiver = v(r.StatusCode)
}
if receiver == nil {
continue
}
if err := dec.Decode(body, receiver); err != nil {
return err
}
}
return nil
}
type bufCloser struct {
bytes.Buffer
}
// Close is a no-op
func (b *bufCloser) Close() error {
return nil
}