From fa11f4ffd3d09e02d746f9c1f3cea133505c13da Mon Sep 17 00:00:00 2001 From: Ruslan Efanov Date: Tue, 25 Oct 2022 17:32:46 +0300 Subject: [PATCH] fix creating errors from response --- v1/client.go | 10 +-------- v1/client_test.go | 6 +++--- v1/errors.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++ v1/errors_test.go | 33 +++++++++++++++++++++++++++++ v1/request.go | 12 +++++------ v1/types.go | 9 +++++--- 6 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 v1/errors.go create mode 100644 v1/errors_test.go diff --git a/v1/client.go b/v1/client.go index 58210ac..c7a9b24 100644 --- a/v1/client.go +++ b/v1/client.go @@ -666,15 +666,7 @@ func (c *MgClient) UploadFileByURL(request UploadFileByUrlRequest) (UploadFileRe } func (c *MgClient) Error(info []byte) error { - var data map[string]interface{} - - if err := json.Unmarshal(info, &data); err != nil { - return err - } - - values := data["errors"].([]interface{}) - - return APIError(values[0].(string)) + return NewAPIClientError(info) } // MakeTimestamp returns current unix timestamp. diff --git a/v1/client_test.go b/v1/client_test.go index b4ab042..442593d 100644 --- a/v1/client_test.go +++ b/v1/client_test.go @@ -683,7 +683,7 @@ func (t *MGClientTest) Test_SuccessHandleAPIError() { client := t.client() handleError := client.Error([]byte(`{"errors": ["Channel not found"]}`)) - t.Assert().IsType(APIError(""), handleError) + t.Assert().IsType(new(httpClientError), handleError) t.Assert().Equal(handleError.Error(), "Channel not found") defer gock.Off() @@ -694,6 +694,6 @@ func (t *MGClientTest) Test_SuccessHandleAPIError() { _, statusCode, err := client.DeactivateTransportChannel(123) t.Assert().Equal(http.StatusInternalServerError, statusCode) - t.Assert().IsType(APIError(""), err) - t.Assert().Equal("http request error. status code: 500", err.Error()) + t.Assert().IsType(new(httpClientError), err) + t.Assert().Equal("Internal server error", err.Error()) } diff --git a/v1/errors.go b/v1/errors.go new file mode 100644 index 0000000..326f455 --- /dev/null +++ b/v1/errors.go @@ -0,0 +1,53 @@ +package v1 + +import ( + "encoding/json" +) + +var defaultErrorMessage = "Internal http client error" +var internalServerError = "Internal server error" + +type httpClientError struct { + ErrorMsg string + BaseError error +} + +func (err *httpClientError) Unwrap() error { + return err.BaseError +} + +func (err *httpClientError) Error() string { + message := defaultErrorMessage + + if err.BaseError != nil { + message = err.BaseError.Error() + } + + if len([]rune(err.ErrorMsg)) > 0 { + message = err.ErrorMsg + } + + return message +} + +func NewCriticalHTTPError(err error) error { + return &httpClientError{BaseError: err} +} + +func NewAPIClientError(responseBody []byte) error { + var data map[string]interface{} + var message string + + if len(responseBody) == 0 { + message = internalServerError + } else { + if err := json.Unmarshal(responseBody, &data); err != nil { + return err + } + + values := data["errors"].([]interface{}) + message = values[0].(string) + } + + return &httpClientError{ErrorMsg: message} +} \ No newline at end of file diff --git a/v1/errors_test.go b/v1/errors_test.go new file mode 100644 index 0000000..130e780 --- /dev/null +++ b/v1/errors_test.go @@ -0,0 +1,33 @@ +package v1 + +import ( + "errors" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewCriticalHTTPError(t *testing.T) { + err := &url.Error{Op: "Get", URL: "http//example.com", Err: errors.New("EOF")} + httpErr := NewCriticalHTTPError(err) + + assert.IsType(t, new(httpClientError), httpErr) + assert.IsType(t, new(url.Error), errors.Unwrap(httpErr)) + assert.IsType(t, new(url.Error), errors.Unwrap(httpErr)) + assert.Equal(t, httpErr.Error(), err.Error()) +} + +func TestNewApiClientError(t *testing.T) { + body := []byte(`{"errors" : ["Channel not found"]}`) + httpErr := NewAPIClientError(body) + + assert.IsType(t, new(httpClientError), httpErr) + assert.Equal(t, httpErr.Error(), "Channel not found") + + body = []byte{} + httpErr = NewAPIClientError(body) + + assert.IsType(t, new(httpClientError), httpErr) + assert.Equal(t, httpErr.Error(), internalServerError) +} \ No newline at end of file diff --git a/v1/request.go b/v1/request.go index 9941291..275327b 100644 --- a/v1/request.go +++ b/v1/request.go @@ -71,12 +71,7 @@ func makeRequest(reqType, url string, buf io.Reader, c *MgClient) ([]byte, int, resp, err := c.httpClient.Do(req) if err != nil { - return res, 0, ClientError(err.Error()) - } - - if resp.StatusCode >= http.StatusInternalServerError { - err = APIError(fmt.Sprintf("http request error. status code: %d", resp.StatusCode)) - return res, resp.StatusCode, err + return res, 0, NewCriticalHTTPError(err) } res, err = buildRawResponse(resp) @@ -84,6 +79,11 @@ func makeRequest(reqType, url string, buf io.Reader, c *MgClient) ([]byte, int, return res, 0, err } + if resp.StatusCode >= http.StatusInternalServerError { + err = NewAPIClientError(res) + return res, resp.StatusCode, err + } + if c.Debug { c.writeLog("MG TRANSPORT API Response: %s", res) } diff --git a/v1/types.go b/v1/types.go index 9504b23..d90d775 100644 --- a/v1/types.go +++ b/v1/types.go @@ -73,11 +73,14 @@ func (err ClientError) Error() string { return string(err) } -// APIError is error from MG. -type APIError string +// APIError is error with 5xx status code. +type APIError struct { + code int + errorMsg string +} func (err APIError) Error() string { - return string(err) + return fmt.Sprintf("Error message: %s, code: %v", err.errorMsg, err.code) } type ErrorType string