diff --git a/restapi.go b/restapi.go index 2e2adf2..d51fcbe 100644 --- a/restapi.go +++ b/restapi.go @@ -169,7 +169,7 @@ func (s *Session) request(method, urlStr, contentType string, b []byte, sequence response, err = s.request(method, urlStr, contentType, b, sequence) default: // Error condition - err = fmt.Errorf("HTTP %s, %s", resp.Status, response) + err = newRestError(req, resp, response) } return diff --git a/structs.go b/structs.go index 3e0c375..47623f4 100644 --- a/structs.go +++ b/structs.go @@ -502,6 +502,12 @@ type UserGuildSettingsEdit struct { ChannelOverrides map[string]*UserGuildSettingsChannelOverride `json:"channel_overrides"` } +// An APIErrorMessage is an api error message returned from discord +type APIErrorMessage struct { + Code int `json:"code"` + Message string `json:"message"` +} + // ChannelPinsUpdate stores data for the channel pins update event type ChannelPinsUpdate struct { LastPinTimestamp string `json:"last_pin_timestamp"` diff --git a/types.go b/types.go index 24f52c4..780b6bb 100644 --- a/types.go +++ b/types.go @@ -10,6 +10,9 @@ package discordgo import ( + "encoding/json" + "fmt" + "net/http" "time" ) @@ -21,3 +24,35 @@ type Timestamp string func (t Timestamp) Parse() (time.Time, error) { return time.Parse(time.RFC3339, string(t)) } + +// RESTError stores error information about a request with a bad response code. +// Message is not always present, there are cases where api calls can fail +// without returning a json message. +type RESTError struct { + Request *http.Request + Response *http.Response + ResponseBody []byte + + Message *APIErrorMessage // Message may be nil. +} + +func newRestError(req *http.Request, resp *http.Response, body []byte) *RESTError { + restErr := &RESTError{ + Request: req, + Response: resp, + ResponseBody: body, + } + + // Attempt to decode the error and assume no message was provided if it fails + var msg *APIErrorMessage + err := json.Unmarshal(body, &msg) + if err == nil { + restErr.Message = msg + } + + return restErr +} + +func (r RESTError) Error() string { + return fmt.Sprintf("HTTP %s, %s", r.Response.Status, r.ResponseBody) +}