diff --git a/httpclient/request.go b/httpclient/request.go index 5bedbe0..bdd8805 100644 --- a/httpclient/request.go +++ b/httpclient/request.go @@ -66,13 +66,13 @@ import ( func (c *Client) DoRequest(method, endpoint string, body, out interface{}) (*http.Response, error) { if !c.config.RetryEligiableRequests { - return c.executeRequest(method, endpoint, body, out) + return c.request(method, endpoint, body, out) } if IsIdempotentHTTPMethod(method) { - return c.executeRequestWithRetries(method, endpoint, body) + return c.requestWithRetries(method, endpoint, body) } else if !IsIdempotentHTTPMethod(method) { - return c.executeRequest(method, endpoint, body, out) + return c.request(method, endpoint, body, out) } else { return nil, fmt.Errorf("unsupported http method: %s", method) } @@ -112,7 +112,7 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}) (*htt // operations. // - The retry mechanism employs exponential backoff with jitter to mitigate the impact of retries on the server. // endregion -func (c *Client) executeRequestWithRetries(method, endpoint string, body interface{}) (*http.Response, error) { +func (c *Client) requestWithRetries(method, endpoint string, body interface{}) (*http.Response, error) { var resp *http.Response var err error var retryCount int @@ -226,26 +226,27 @@ func (c *Client) executeRequestWithRetries(method, endpoint string, body interfa // any errors encountered. // // endregion -func (c *Client) executeRequest(method, endpoint string, body, out interface{}) (*http.Response, error) { +func (c *Client) request(method, endpoint string, body, out interface{}) (*http.Response, error) { // TODO review refactor execute Request ctx := context.Background() c.Sugar.Debug("Executing request without retries", zap.String("method", method), zap.String("endpoint", endpoint)) - res, err := c.doRequest(ctx, method, endpoint, body) + resp, err := c.doRequest(ctx, method, endpoint, body) if err != nil { return nil, err } - if res.StatusCode >= 200 && res.StatusCode < 400 { - if res.StatusCode >= 300 { - c.Sugar.Warn("Redirect response received", zap.Int("status_code", res.StatusCode), zap.String("location", res.Header.Get("Location"))) + if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusBadRequest { + if resp.StatusCode == http.StatusPermanentRedirect || resp.StatusCode == http.StatusTemporaryRedirect { + c.Sugar.Warn("Redirect response received", zap.Int("status_code", resp.StatusCode), zap.String("location", resp.Header.Get("Location"))) } - return res, response.HandleAPISuccessResponse(res, out, c.Sugar) + c.Sugar.Infof("%s request successful at %v", resp.Request.Method, resp.Request.URL) + return resp, nil } - return nil, response.HandleAPIErrorResponse(res, c.Sugar) + return nil, response.HandleAPIErrorResponse(resp, c.Sugar) } func (c *Client) doRequest(ctx context.Context, method, endpoint string, body interface{}) (*http.Response, error) { diff --git a/response/error.go b/response/error.go index bdc41ce..46f0e39 100644 --- a/response/error.go +++ b/response/error.go @@ -60,13 +60,13 @@ func HandleAPIErrorResponse(resp *http.Response, sugar *zap.SugaredLogger) *APIE mimeType, _ := ParseContentTypeHeader(resp.Header.Get("Content-Type")) switch mimeType { case "application/json": - parseJSONResponse(bodyBytes, apiError, resp, sugar) + parseJSONResponse(bodyBytes, apiError) case "application/xml", "text/xml": - parseXMLResponse(bodyBytes, apiError, resp, sugar) + parseXMLResponse(bodyBytes, apiError) case "text/html": - parseHTMLResponse(bodyBytes, apiError, resp, sugar) + parseHTMLResponse(bodyBytes, apiError) case "text/plain": - parseTextResponse(bodyBytes, apiError, resp, sugar) + parseTextResponse(bodyBytes, apiError) default: apiError.RawResponse = string(bodyBytes) apiError.Message = "Unknown content type error" @@ -76,7 +76,7 @@ func HandleAPIErrorResponse(resp *http.Response, sugar *zap.SugaredLogger) *APIE } // parseJSONResponse attempts to parse the JSON error response and update the APIError structure. -func parseJSONResponse(bodyBytes []byte, apiError *APIError, resp *http.Response, sugar *zap.SugaredLogger) { +func parseJSONResponse(bodyBytes []byte, apiError *APIError) { if err := json.Unmarshal(bodyBytes, apiError); err != nil { apiError.RawResponse = string(bodyBytes) } else { @@ -88,7 +88,7 @@ func parseJSONResponse(bodyBytes []byte, apiError *APIError, resp *http.Response } // parseXMLResponse dynamically parses XML error responses and accumulates potential error messages. -func parseXMLResponse(bodyBytes []byte, apiError *APIError, resp *http.Response, sugar *zap.SugaredLogger) { +func parseXMLResponse(bodyBytes []byte, apiError *APIError) { // Always set the Raw field to the entire XML content for debugging purposes. apiError.RawResponse = string(bodyBytes) @@ -121,7 +121,7 @@ func parseXMLResponse(bodyBytes []byte, apiError *APIError, resp *http.Response, } // parseTextResponse updates the APIError structure based on a plain text error response and logs it. -func parseTextResponse(bodyBytes []byte, apiError *APIError, resp *http.Response, sugar *zap.SugaredLogger) { +func parseTextResponse(bodyBytes []byte, apiError *APIError) { // Convert the body bytes to a string and assign it to both the message and RawResponse fields of APIError. bodyText := string(bodyBytes) apiError.RawResponse = bodyText @@ -133,7 +133,7 @@ func parseTextResponse(bodyBytes []byte, apiError *APIError, resp *http.Response // parseHTMLResponse extracts meaningful information from an HTML error response, // concatenating all text within
tags and links found within them. -func parseHTMLResponse(bodyBytes []byte, apiError *APIError, resp *http.Response, sugar *zap.SugaredLogger) { +func parseHTMLResponse(bodyBytes []byte, apiError *APIError) { // Set the entire HTML content as the RawResponse for debugging purposes. apiError.RawResponse = string(bodyBytes) diff --git a/response/success.go b/response/success.go index 3f149eb..aa03b9d 100644 --- a/response/success.go +++ b/response/success.go @@ -52,7 +52,7 @@ func HandleAPISuccessResponse(resp *http.Response, out interface{}, sugar *zap.S if handler, ok := responseUnmarshallers[mimeType]; ok { return handler(bodyReader, out, sugar, mimeType) } else if isBinaryData(mimeType, contentDisposition) { - return handleBinaryData(bodyReader, sugar, out, mimeType, contentDisposition) + return handleBinaryData(bodyReader, sugar, out, contentDisposition) } else { errMsg := fmt.Sprintf("unexpected MIME type: %s", mimeType) sugar.Error("Unmarshal error", zap.String("content type", mimeType), zap.Error(errors.New(errMsg))) @@ -97,7 +97,7 @@ func isBinaryData(contentType, contentDisposition string) bool { } // handleBinaryData reads binary data from an io.Reader and stores it in *[]byte or streams it to an io.Writer. -func handleBinaryData(reader io.Reader, sugar *zap.SugaredLogger, out interface{}, mimeType, contentDisposition string) error { +func handleBinaryData(reader io.Reader, sugar *zap.SugaredLogger, out interface{}, contentDisposition string) error { // Check if the output interface is either *[]byte or io.Writer switch out := out.(type) { case *[]byte: