forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
73 lines (64 loc) · 1.99 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
package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Response is a raw response that wraps an HTTP response.
type Response struct {
*http.Response
}
// DecodeJSON will decode the response body to a JSON structure. This
// will consume the response body, but will not close it. Close must
// still be called.
func (r *Response) DecodeJSON(out interface{}) error {
dec := json.NewDecoder(r.Body)
return dec.Decode(out)
}
// Error returns an error response if there is one. If there is an error,
// this will fully consume the response body, but will not close it. The
// body must still be closed manually.
func (r *Response) Error() error {
// 200 to 399 are okay status codes
if r.StatusCode >= 200 && r.StatusCode < 400 {
return nil
}
// We have an error. Let's copy the body into our own buffer first,
// so that if we can't decode JSON, we can at least copy it raw.
var bodyBuf bytes.Buffer
if _, err := io.Copy(&bodyBuf, r.Body); err != nil {
return err
}
// Decode the error response if we can. Note that we wrap the bodyBuf
// in a bytes.Reader here so that the JSON decoder doesn't move the
// read pointer for the original buffer.
var resp ErrorResponse
dec := json.NewDecoder(bytes.NewReader(bodyBuf.Bytes()))
if err := dec.Decode(&resp); err != nil {
// Ignore the decoding error and just drop the raw response
return fmt.Errorf(
"Error making API request.\n\n"+
"URL: %s %s\n"+
"Code: %d. Raw Message:\n\n%s",
r.Request.Method, r.Request.URL.String(),
r.StatusCode, bodyBuf.String())
}
var errBody bytes.Buffer
errBody.WriteString(fmt.Sprintf(
"Error making API request.\n\n"+
"URL: %s %s\n"+
"Code: %d. Errors:\n\n",
r.Request.Method, r.Request.URL.String(),
r.StatusCode))
for _, err := range resp.Errors {
errBody.WriteString(fmt.Sprintf("* %s", err))
}
return fmt.Errorf(errBody.String())
}
// ErrorResponse is the raw structure of errors when they're returned by the
// HTTP API.
type ErrorResponse struct {
Errors []string
}