diff --git a/response/error.go b/response/error.go index 7b69320..2e95bc0 100644 --- a/response/error.go +++ b/response/error.go @@ -17,12 +17,12 @@ import ( // APIError represents an api error response. type APIError struct { - StatusCode int `json:"status_code"` // HTTP status code - Type string `json:"type"` // Type of error - Message string `json:"message"` // Human-readable message - Detail string `json:"detail,omitempty"` // Detailed error message - Errors map[string]interface{} `json:"errors,omitempty"` // Additional error details - Raw string `json:"raw"` // Raw response body for debugging + StatusCode int `json:"status_code"` // HTTP status code + Method string `json:"method"` // HTTP method used for the request + URL string `json:"url"` // The URL of the HTTP request + Message string `json:"message"` // Summary of the error + Details []string `json:"details"` // Detailed error messages, if any + RawResponse string `json:"raw_response"` // Raw response body for debugging } // Error returns a string representation of the APIError, making it compatible with the error interface. @@ -39,21 +39,22 @@ func (e *APIError) Error() string { } // Fallback to a simpler error message format if JSON marshaling fails. - return fmt.Sprintf("API Error: StatusCode=%d, Type=%s, Message=%s", e.StatusCode, e.Type, e.Message) + return fmt.Sprintf("API Error: StatusCode=%d, Message=%s", e.StatusCode, e.Message) } // HandleAPIErrorResponse handles the HTTP error response from an API and logs the error. func HandleAPIErrorResponse(resp *http.Response, log logger.Logger) *APIError { apiError := &APIError{ StatusCode: resp.StatusCode, - Type: "API Error Response", - Message: "An error occurred", + Method: resp.Request.Method, + URL: resp.Request.URL.String(), + Message: "API Error Response", } bodyBytes, err := io.ReadAll(resp.Body) if err != nil { - apiError.Raw = "Failed to read response body" - log.LogError("error_reading_response_body", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.Raw) + apiError.RawResponse = "Failed to read response body" + log.LogError("error_reading_response_body", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.RawResponse) return apiError } @@ -68,9 +69,9 @@ func HandleAPIErrorResponse(resp *http.Response, log logger.Logger) *APIError { case "text/plain": parseTextResponse(bodyBytes, apiError, log, resp) default: - apiError.Raw = string(bodyBytes) + apiError.RawResponse = string(bodyBytes) apiError.Message = "Unknown content type error" - log.LogError("unknown_content_type_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, "Unknown content type", nil, apiError.Raw) + log.LogError("unknown_content_type_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, "Unknown content type", nil, apiError.RawResponse) } return apiError @@ -93,28 +94,26 @@ func ParseContentTypeHeader(header string) (string, map[string]string) { // parseJSONResponse attempts to parse the JSON error response and update the APIError structure. func parseJSONResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) { if err := json.Unmarshal(bodyBytes, apiError); err != nil { - apiError.Raw = string(bodyBytes) - logError(log, apiError, "json_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err) + apiError.RawResponse = string(bodyBytes) + log.LogError("json_parsing_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.RawResponse) } else { if apiError.Message == "" { apiError.Message = "An unknown error occurred" } - // Log the detected JSON error with all the context information. - logError(log, apiError, "json_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, nil) + log.LogError("json_error_detected", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.RawResponse) } } // parseXMLResponse dynamically parses XML error responses and accumulates potential error messages. func parseXMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) { // Always set the Raw field to the entire XML content for debugging purposes. - apiError.Raw = string(bodyBytes) + apiError.RawResponse = string(bodyBytes) // Parse the XML document. doc, err := xmlquery.Parse(bytes.NewReader(bodyBytes)) if err != nil { - // Log the XML parsing error with all the context information. - logError(log, apiError, "xml_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err) + log.LogError("xml_parsing_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.RawResponse) return } @@ -141,37 +140,41 @@ func parseXMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, r // Determine the error to log based on whether a message was found. var logErr error if apiError.Message == "" { - logErr = fmt.Errorf("No error message extracted from XML") + logErr = fmt.Errorf("no error message extracted from XML") } - // Log the error or the lack of extracted messages using the centralized logger. - logError(log, apiError, "xml_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, logErr) + log.LogError("html_parsing_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, logErr, apiError.RawResponse) } // parseTextResponse updates the APIError structure based on a plain text error response and logs it. func parseTextResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) { + // Convert the body bytes to a string and assign it to both the message and RawResponse fields of APIError. bodyText := string(bodyBytes) - apiError.Raw = bodyText - - // Check if the 'Message' field of APIError is empty and use the body text as the message. - if apiError.Message == "" { - apiError.Message = bodyText - } - - // Use the updated logError function with the additional parameters. - logError(log, apiError, "text_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, nil) + apiError.RawResponse = bodyText + + // Directly use the body text as the error message if the Message field is empty. + apiError.Message = bodyText + + log.LogError( + "text_error_detected", // Event + resp.Request.Method, // HTTP method + resp.Request.URL.String(), // Request URL + apiError.StatusCode, // HTTP status code + resp.Status, // HTTP status message from the response + nil, // Error (nil because text parsing is unlikely to fail) + apiError.RawResponse, // Raw response text + ) } // parseHTMLResponse extracts meaningful information from an HTML error response and concatenates all text within
tags. func parseHTMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) { // Always set the Raw field to the entire HTML content for debugging purposes. - apiError.Raw = string(bodyBytes) + apiError.RawResponse = string(bodyBytes) reader := bytes.NewReader(bodyBytes) doc, err := html.Parse(reader) if err != nil { - // Log HTML parsing error using centralized logger with context. - logError(log, apiError, "html_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err) + log.LogError("html_parsing_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.RawResponse) return } @@ -212,40 +215,10 @@ func parseHTMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, // Determine the error to log based on whether a message was found. var logErr error if apiError.Message == "" { - logErr = fmt.Errorf("No error message extracted from HTML") + logErr = fmt.Errorf("no error message extracted from HTML") } // Log the extracted error message or the fallback message using the centralized logger. - logError(log, apiError, "html_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, logErr) -} - -// logError logs the error details using the provided logger instance. -// func logError(log logger.Logger, apiError *APIError, event string, resp *http.Response) { -// // Prepare the error message. If apiError.Message is empty, use a default message. -// errorMessage := apiError.Message -// if errorMessage == "" { -// errorMessage = "An unspecified error occurred" -// } - -// // Use LogError method from the logger package for error logging. -// log.LogError( -// event, -// resp.Request.Method, -// resp.Request.URL.String(), -// apiError.StatusCode, -// resp.Status, -// fmt.Errorf(errorMessage), -// apiError.Raw, -// ) -// } - -func logError(log logger.Logger, apiError *APIError, event, method, url, statusMessage string, err error) { - // Prepare the error message. If apiError.Message is empty, use a default message. - errorMessage := apiError.Message - if errorMessage == "" { - errorMessage = "An unspecified error occurred" - } + log.LogError("html_error_detected", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, logErr, apiError.RawResponse) - // Call the LogError method from the logger package for error logging. - log.LogError(event, method, url, apiError.StatusCode, statusMessage, err, apiError.Raw) }