2015-03-11 18:33:20 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2015-03-11 18:43:49 +00:00
|
|
|
"bytes"
|
2015-03-11 18:33:20 +00:00
|
|
|
"encoding/json"
|
2015-03-11 18:43:49 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2015-03-11 18:33:20 +00:00
|
|
|
"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)
|
2016-04-20 18:38:20 +00:00
|
|
|
dec.UseNumber()
|
2015-03-11 18:33:20 +00:00
|
|
|
return dec.Decode(out)
|
|
|
|
}
|
2015-03-11 18:43:49 +00:00
|
|
|
|
|
|
|
// 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()))
|
2016-04-20 18:38:20 +00:00
|
|
|
dec.UseNumber()
|
2015-03-11 18:43:49 +00:00
|
|
|
if err := dec.Decode(&resp); err != nil {
|
|
|
|
// Ignore the decoding error and just drop the raw response
|
|
|
|
return fmt.Errorf(
|
2015-03-16 17:51:13 +00:00
|
|
|
"Error making API request.\n\n"+
|
|
|
|
"URL: %s %s\n"+
|
|
|
|
"Code: %d. Raw Message:\n\n%s",
|
|
|
|
r.Request.Method, r.Request.URL.String(),
|
2015-03-11 18:43:49 +00:00
|
|
|
r.StatusCode, bodyBuf.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
var errBody bytes.Buffer
|
|
|
|
errBody.WriteString(fmt.Sprintf(
|
2015-03-16 17:51:13 +00:00
|
|
|
"Error making API request.\n\n"+
|
|
|
|
"URL: %s %s\n"+
|
|
|
|
"Code: %d. Errors:\n\n",
|
|
|
|
r.Request.Method, r.Request.URL.String(),
|
|
|
|
r.StatusCode))
|
2015-03-11 18:43:49 +00:00
|
|
|
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
|
|
|
|
}
|