Skip to content

Commit 08bc4b1

Browse files
authored
Merge pull request #135 from deploymenttheory/dev
Refactor code to improve performance and readability
2 parents 907e849 + ccdc6f4 commit 08bc4b1

File tree

1 file changed

+77
-51
lines changed

1 file changed

+77
-51
lines changed

Diff for: response/error.go

+77-51
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ import (
1717

1818
// APIError represents an api error response.
1919
type APIError struct {
20-
StatusCode int `json:"status_code" xml:"StatusCode"` // HTTP status code
21-
Type string `json:"type" xml:"Type"` // Type of error
22-
Message string `json:"message" xml:"Message"` // Human-readable message
23-
Detail string `json:"detail,omitempty" xml:"Detail,omitempty"` // Detailed error message
24-
Errors map[string]interface{} `json:"errors,omitempty" xml:"Errors,omitempty"` // Additional error details
25-
Raw string `json:"raw" xml:"Raw"` // Raw response body for debugging
20+
StatusCode int `json:"status_code"` // HTTP status code
21+
Type string `json:"type"` // Type of error
22+
Message string `json:"message"` // Human-readable message
23+
Detail string `json:"detail,omitempty"` // Detailed error message
24+
Errors map[string]interface{} `json:"errors,omitempty"` // Additional error details
25+
Raw string `json:"raw"` // Raw response body for debugging
2626
}
2727

2828
// Error returns a string representation of the APIError, making it compatible with the error interface.
@@ -46,14 +46,14 @@ func (e *APIError) Error() string {
4646
func HandleAPIErrorResponse(resp *http.Response, log logger.Logger) *APIError {
4747
apiError := &APIError{
4848
StatusCode: resp.StatusCode,
49-
Type: "APIError",
49+
Type: "API Error Response",
5050
Message: "An error occurred",
5151
}
5252

5353
bodyBytes, err := io.ReadAll(resp.Body)
5454
if err != nil {
5555
apiError.Raw = "Failed to read response body"
56-
logError(log, apiError, "error_reading_response_body", resp)
56+
log.LogError("error_reading_response_body", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, resp.Status, err, apiError.Raw)
5757
return apiError
5858
}
5959

@@ -70,7 +70,7 @@ func HandleAPIErrorResponse(resp *http.Response, log logger.Logger) *APIError {
7070
default:
7171
apiError.Raw = string(bodyBytes)
7272
apiError.Message = "Unknown content type error"
73-
logError(log, apiError, "unknown_content_type_error", resp)
73+
log.LogError("unknown_content_type_error", resp.Request.Method, resp.Request.URL.String(), apiError.StatusCode, "Unknown content type", nil, apiError.Raw)
7474
}
7575

7676
return apiError
@@ -94,29 +94,27 @@ func ParseContentTypeHeader(header string) (string, map[string]string) {
9494
func parseJSONResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) {
9595
if err := json.Unmarshal(bodyBytes, apiError); err != nil {
9696
apiError.Raw = string(bodyBytes)
97-
log.LogError("json_parsing_error",
98-
resp.Request.Method,
99-
resp.Request.URL.String(),
100-
resp.StatusCode,
101-
"JSON parsing failed",
102-
err,
103-
apiError.Raw,
104-
)
97+
logError(log, apiError, "json_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err)
10598
} else {
106-
// Successfully parsed JSON error, so log the error details.
107-
logError(log, apiError, "json_error_detected", resp)
99+
if apiError.Message == "" {
100+
apiError.Message = "An unknown error occurred"
101+
}
102+
103+
// Log the detected JSON error with all the context information.
104+
logError(log, apiError, "json_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, nil)
108105
}
109106
}
110107

111108
// parseXMLResponse dynamically parses XML error responses and accumulates potential error messages.
112109
func parseXMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) {
113-
// Always set the Raw field to the entire XML content for debugging purposes
110+
// Always set the Raw field to the entire XML content for debugging purposes.
114111
apiError.Raw = string(bodyBytes)
115112

116-
// Parse the XML document
113+
// Parse the XML document.
117114
doc, err := xmlquery.Parse(bytes.NewReader(bodyBytes))
118115
if err != nil {
119-
logError(log, apiError, "xml_parsing_error", resp)
116+
// Log the XML parsing error with all the context information.
117+
logError(log, apiError, "xml_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err)
120118
return
121119
}
122120

@@ -133,93 +131,121 @@ func parseXMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, r
133131

134132
traverse(doc)
135133

136-
// Concatenate all messages found in the XML for the 'Message' field of APIError
134+
// Concatenate all messages found in the XML for the 'Message' field of APIError.
137135
if len(messages) > 0 {
138136
apiError.Message = strings.Join(messages, "; ")
139137
} else {
140-
// Fallback error message if no specific messages were extracted
141138
apiError.Message = "Failed to extract error details from XML response"
142139
}
143140

144-
// Log the error using the centralized logger
145-
logError(log, apiError, "xml_error_detected", resp)
141+
// Determine the error to log based on whether a message was found.
142+
var logErr error
143+
if apiError.Message == "" {
144+
logErr = fmt.Errorf("No error message extracted from XML")
145+
}
146+
147+
// Log the error or the lack of extracted messages using the centralized logger.
148+
logError(log, apiError, "xml_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, logErr)
146149
}
147150

148151
// parseTextResponse updates the APIError structure based on a plain text error response and logs it.
149152
func parseTextResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) {
150153
bodyText := string(bodyBytes)
151-
apiError.Message = bodyText
152154
apiError.Raw = bodyText
153-
// Log the plain text error using the centralized logger.
154-
logError(log, apiError, "text_error_detected", resp)
155+
156+
// Check if the 'Message' field of APIError is empty and use the body text as the message.
157+
if apiError.Message == "" {
158+
apiError.Message = bodyText
159+
}
160+
161+
// Use the updated logError function with the additional parameters.
162+
logError(log, apiError, "text_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, nil)
155163
}
156164

157165
// parseHTMLResponse extracts meaningful information from an HTML error response and concatenates all text within <p> tags.
158166
func parseHTMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger, resp *http.Response) {
159-
// Always set the Raw field to the entire HTML content for debugging purposes
167+
// Always set the Raw field to the entire HTML content for debugging purposes.
160168
apiError.Raw = string(bodyBytes)
161169

162170
reader := bytes.NewReader(bodyBytes)
163171
doc, err := html.Parse(reader)
164172
if err != nil {
165-
logError(log, apiError, "html_parsing_error", resp)
173+
// Log HTML parsing error using centralized logger with context.
174+
logError(log, apiError, "html_parsing_error", resp.Request.Method, resp.Request.URL.String(), resp.Status, err)
166175
return
167176
}
168177

169-
var messages []string // To accumulate messages from all <p> tags
178+
var messages []string // To accumulate messages from all <p> tags.
170179
var parse func(*html.Node)
171180
parse = func(n *html.Node) {
172181
if n.Type == html.ElementNode && n.Data == "p" {
173182
var pText strings.Builder
174183
for c := n.FirstChild; c != nil; c = c.NextSibling {
175184
if c.Type == html.TextNode && strings.TrimSpace(c.Data) != "" {
176-
// Build text content of <p> tag
185+
// Build text content of <p> tag.
177186
if pText.Len() > 0 {
178-
pText.WriteString(" ") // Add a space between text nodes within the same <p> tag
187+
pText.WriteString(" ") // Add a space between text nodes within the same <p> tag.
179188
}
180189
pText.WriteString(strings.TrimSpace(c.Data))
181190
}
182191
}
183192
if pText.Len() > 0 {
184-
// Add the built text content of the <p> tag to messages
193+
// Add the built text content of the <p> tag to messages.
185194
messages = append(messages, pText.String())
186195
}
187196
}
188197
for c := n.FirstChild; c != nil; c = c.NextSibling {
189-
parse(c) // Recursively parse the document
198+
parse(c) // Recursively parse the document.
190199
}
191200
}
192201

193202
parse(doc)
194203

195-
// Concatenate all accumulated messages with a separator
204+
// Concatenate all accumulated messages with a separator.
196205
if len(messages) > 0 {
197206
apiError.Message = strings.Join(messages, "; ")
198207
} else {
199-
// Fallback error message if no specific messages were extracted
208+
// Fallback error message if no specific messages were extracted.
200209
apiError.Message = "HTML Error: See 'Raw' field for details."
201210
}
202211

203-
// Log the extracted error message or the fallback message
204-
logError(log, apiError, "html_error_detected", resp)
212+
// Determine the error to log based on whether a message was found.
213+
var logErr error
214+
if apiError.Message == "" {
215+
logErr = fmt.Errorf("No error message extracted from HTML")
216+
}
217+
218+
// Log the extracted error message or the fallback message using the centralized logger.
219+
logError(log, apiError, "html_error_detected", resp.Request.Method, resp.Request.URL.String(), resp.Status, logErr)
205220
}
206221

207222
// logError logs the error details using the provided logger instance.
208-
func logError(log logger.Logger, apiError *APIError, event string, resp *http.Response) {
223+
// func logError(log logger.Logger, apiError *APIError, event string, resp *http.Response) {
224+
// // Prepare the error message. If apiError.Message is empty, use a default message.
225+
// errorMessage := apiError.Message
226+
// if errorMessage == "" {
227+
// errorMessage = "An unspecified error occurred"
228+
// }
229+
230+
// // Use LogError method from the logger package for error logging.
231+
// log.LogError(
232+
// event,
233+
// resp.Request.Method,
234+
// resp.Request.URL.String(),
235+
// apiError.StatusCode,
236+
// resp.Status,
237+
// fmt.Errorf(errorMessage),
238+
// apiError.Raw,
239+
// )
240+
// }
241+
242+
func logError(log logger.Logger, apiError *APIError, event, method, url, statusMessage string, err error) {
209243
// Prepare the error message. If apiError.Message is empty, use a default message.
210244
errorMessage := apiError.Message
211245
if errorMessage == "" {
212246
errorMessage = "An unspecified error occurred"
213247
}
214248

215-
// Use LogError method from the logger package for error logging.
216-
log.LogError(
217-
event,
218-
resp.Request.Method,
219-
resp.Request.URL.String(),
220-
apiError.StatusCode,
221-
resp.Status,
222-
fmt.Errorf(errorMessage),
223-
apiError.Raw,
224-
)
249+
// Call the LogError method from the logger package for error logging.
250+
log.LogError(event, method, url, apiError.StatusCode, statusMessage, err, apiError.Raw)
225251
}

0 commit comments

Comments
 (0)