From 8f46d993e28216ed8cab17f1a36eac80a16a13c7 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sun, 13 Jul 2014 10:27:02 +0100 Subject: [PATCH] Preserve HTTP staus codes in errors if possible Dropbox being a REST driven service often returns useful information in the HTTP error code. Make sure we return these in a custom Error type if possible. --- dropbox.go | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/dropbox.go b/dropbox.go index 836b907..9157543 100644 --- a/dropbox.go +++ b/dropbox.go @@ -231,6 +231,31 @@ func (db *Dropbox) Auth() error { return err } +// Error - all errors generated by HTTP transactions are of this type. +// Other error may be passed on from library functions though. +type Error struct { + StatusCode int // HTTP status code + Text string +} + +// Error satisfy the error interface. +func (e *Error) Error() string { + return e.Text +} + +// newError make a new error from a string. +func newError(StatusCode int, Text string) *Error { + return &Error{ + StatusCode: StatusCode, + Text: Text, + } +} + +// newErrorf makes a new error from sprintf parameters. +func newErrorf(StatusCode int, Text string, Parameters ...interface{}) *Error { + return newError(StatusCode, fmt.Sprintf(Text, Parameters...)) +} + func getResponse(r *http.Response) ([]byte, error) { var e requestError var b []byte @@ -245,17 +270,17 @@ func getResponse(r *http.Response) ([]byte, error) { if err = json.Unmarshal(b, &e); err == nil { switch v := e.Error.(type) { case string: - return nil, fmt.Errorf("%s", v) + return nil, newErrorf(r.StatusCode, "%s", v) case map[string]interface{}: for param, reason := range v { if reasonstr, ok := reason.(string); ok { - return nil, fmt.Errorf("%s: %s", param, reasonstr) + return nil, newErrorf(r.StatusCode, "%s: %s", param, reasonstr) } } - return nil, fmt.Errorf("wrong parameter") + return nil, newErrorf(r.StatusCode, "wrong parameter") } } - return nil, fmt.Errorf("unexpected HTTP status code %d", r.StatusCode) + return nil, newErrorf(r.StatusCode, "unexpected HTTP status code %d") } // CommitChunkedUpload ends the chunked upload by giving a name to the UploadID. @@ -435,7 +460,7 @@ func (db *Dropbox) Thumbnails(src, format, size string) (io.ReadCloser, int64, * return nil, 0, nil, os.ErrNotExist case http.StatusUnsupportedMediaType: response.Body.Close() - return nil, 0, nil, fmt.Errorf("the image located at '%s' cannot be converted to a thumbnail", src) + return nil, 0, nil, newErrorf(response.StatusCode, "the image located at '%s' cannot be converted to a thumbnail", src) } json.Unmarshal([]byte(response.Header.Get("x-dropbox-metadata")), &entry) return response.Body, response.ContentLength, &entry, err