-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
98 lines (83 loc) · 2.15 KB
/
errors.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
package central
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime"
"net/http"
"github.com/pkg/errors"
)
func isStatus(err error, status int) bool {
e, ok := err.(*Error)
return ok && e.Resp.StatusCode == status
}
type Error struct {
Req *http.Request
Resp *http.Response
Body string
Message string
}
func (e *Error) Error() string {
limit := 500
body := e.Body
if len(body) > limit {
body = body[0:limit] + fmt.Sprintf("... [%d more bytes]", limit-len(body))
}
return fmt.Sprintf("%s: Request [%s %s] failed with status %d (%s): %s",
e.Message, e.Req.Method, e.Req.URL, e.Resp.StatusCode, e.Resp.Status, e.Body)
}
func errorFromResponse(req *http.Request, resp *http.Response, message string, format ...interface{}) (error, bool) {
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
return nil, false
}
defer func() {
if resp.Body != nil {
_ = resp.Body.Close()
}
}()
var body string
if resp.Body != nil {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
body = fmt.Sprintf("[error reading response body: %s]", err)
} else if len(b) > 0 {
body = string(b)
} else {
body = "[no data in response]"
}
}
return &Error{
Resp: resp,
Req: req,
Body: body,
Message: fmt.Sprintf(message, format...),
}, true
}
// decodeResponseAsJSON decodes a HTTP client response as JSON.
func decodeResponseAsJSON(
resp *http.Response,
body io.Reader,
out interface{}) error {
if resp.ContentLength == 0 {
// We treat this is as a non-error
return nil
}
contentType := resp.Header.Get("Content-Type")
if contentType == "" {
return errors.New("expected response to be JSON, received bytes")
}
if mediaType, _, err := mime.ParseMediaType(contentType); err != nil {
return fmt.Errorf("invalid content type %q: %w", contentType, err)
} else if mediaType != "application/json" {
return fmt.Errorf("expected response to be JSON, got %q", mediaType)
}
b, err := ioutil.ReadAll(body)
if err != nil {
return fmt.Errorf("could not read entire response: %w", err)
}
if err := json.Unmarshal(b, out); err != nil {
return fmt.Errorf("could not decode response JSON: %w", err)
}
return nil
}