package client import ( "encoding/json" "io/ioutil" "net/http" "strings" ) // APIError errors that may return from the Client. type APIError struct { Response *http.Response Body json.RawMessage // may be any []byte, response body is closed at this point. } // Error implements the standard error type. func (e APIError) Error() string { var b strings.Builder if e.Response != nil { b.WriteString(e.Response.Request.URL.String()) b.WriteByte(':') b.WriteByte(' ') b.WriteString(http.StatusText(e.Response.StatusCode)) b.WriteByte(' ') b.WriteByte('(') b.WriteString(e.Response.Status) b.WriteByte(')') if len(e.Body) > 0 { b.WriteByte(':') b.WriteByte(' ') b.Write(e.Body) } } return b.String() } // ExtractError returns the response wrapped inside an APIError. func ExtractError(resp *http.Response) APIError { body, _ := ioutil.ReadAll(resp.Body) return APIError{ Response: resp, Body: body, } } // GetError reports whether the given "err" is an APIError. func GetError(err error) (APIError, bool) { if err == nil { return APIError{}, false } apiErr, ok := err.(APIError) if !ok { return APIError{}, false } return apiErr, true } // DecodeError binds a json error to the "destPtr". func DecodeError(err error, destPtr interface{}) error { apiErr, ok := GetError(err) if !ok { return err } return json.Unmarshal(apiErr.Body, destPtr) } // GetErrorCode reads an error, which should be a type of APIError, // and returns its status code. // If the given "err" is nil or is not an APIError it returns 200, acting as we have no error. func GetErrorCode(err error) int { apiErr, ok := GetError(err) if !ok { return http.StatusOK } return apiErr.Response.StatusCode }