From a8da2361cf89048c1a5c356bcf698147904819c7 Mon Sep 17 00:00:00 2001 From: mehanizm Date: Fri, 25 Mar 2022 09:28:05 +0300 Subject: [PATCH] impr: more verbose http api status errors --- errors.go | 30 ++++++++++++++++++++++++++++-- errors_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/errors.go b/errors.go index 278bf12..7446ab1 100644 --- a/errors.go +++ b/errors.go @@ -24,11 +24,37 @@ func (e *HTTPClientError) Error() string { func makeHTTPClientError(url string, resp *http.Response) error { var resError error + respStatusText := "Unknown status text" + switch resp.StatusCode { + case 400: + respStatusText = "The request encoding is invalid; the request can't be parsed as a valid JSON." + case 401: + respStatusText = "Accessinga protected resource without authorization or with invalid credentials." + case 402: + respStatusText = "The account associated with the API key making requests hits a quota that can be increased by upgrading the Airtable account plan." + case 403: + respStatusText = "Accessing a protected resource with API credentials that don't have access to that resource." + case 404: + respStatusText = "Route or resource is not found. This error is returned when the request hits an undefined route, or if the resource doesn't exist (e.g. has been deleted)." + case 413: + respStatusText = "Too Large The request exceeded the maximum allowed payload size. You shouldn't encounter this under normal use." + case 422: + respStatusText = "The request data is invalid. This includes most of the base-specific validations. You will receive a detailed error message and code pointing to the exact issue." + case 500: + respStatusText = "Error The server encountered an unexpected condition." + case 502: + respStatusText = "Airtable's servers are restarting or an unexpected outage is in progress. You should generally not receive this error, and requests are safe to retry." + case 503: + respStatusText = "The server could not process your request in time. The server could be temporarily unavailable, or it could have timed out processing your request. You should retry the request with backoffs." + } + body, err := ioutil.ReadAll(resp.Body) if err != nil { - resError = fmt.Errorf("HTTP request failure on %s with status %d\nCannot parse body with: %w", url, resp.StatusCode, err) + resError = fmt.Errorf("HTTP request failure on %s:\n%d %s\n%s\n\nCannot parse body with err: %w", + url, resp.StatusCode, resp.Status, respStatusText, err) } else { - resError = fmt.Errorf("HTTP request failure on %s with status %d\nBody: %v", url, resp.StatusCode, string(body)) + resError = fmt.Errorf("HTTP request failure on %s:\n%d %s\n%s\n\nBody: %v", + url, resp.StatusCode, resp.Status, respStatusText, string(body)) } return &HTTPClientError{ diff --git a/errors_test.go b/errors_test.go index 7cc750e..70728fb 100644 --- a/errors_test.go +++ b/errors_test.go @@ -6,7 +6,10 @@ package airtable import ( + "bytes" "errors" + "io" + "net/http" "testing" ) @@ -20,3 +23,34 @@ func TestHTTPClientError_Error(t *testing.T) { t.Errorf("HTTPClientError.Error() = %v, want %v", got, expected) } } + +func Test_makeHTTPClientError(t *testing.T) { + tests := []struct { + name string + url string + resp *http.Response + expected string + }{ + { + name: "400", + url: "google.com", + resp: &http.Response{ + StatusCode: 400, + Status: "Bad Request", + Body: io.NopCloser(bytes.NewReader([]byte("body"))), + }, + expected: `status 400, err: HTTP request failure on google.com: +400 Bad Request +The request encoding is invalid; the request can't be parsed as a valid JSON. + +Body: body`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := makeHTTPClientError(tt.url, tt.resp); err.Error() != tt.expected { + t.Errorf("makeHTTPClientError() error:\n%v\n\nexpected:\n%v", err, tt.expected) + } + }) + } +}