Skip to content

Commit 907e849

Browse files
authored
Merge pull request #134 from deploymenttheory/dev
Moved error responses from the api integration to a centralised response package
2 parents ca10057 + 6ef28b5 commit 907e849

File tree

5 files changed

+92
-83
lines changed

5 files changed

+92
-83
lines changed

apiintegrations/apihandler/apihandler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type APIHandler interface {
1818
MarshalRequest(body interface{}, method string, endpoint string, log logger.Logger) ([]byte, error)
1919
MarshalMultipartRequest(fields map[string]string, files map[string]string, log logger.Logger) ([]byte, string, error)
2020
HandleAPISuccessResponse(resp *http.Response, out interface{}, log logger.Logger) error
21-
HandleAPIErrorResponse(resp *http.Response, out interface{}, log logger.Logger) error
21+
//HandleAPIErrorResponse(resp *http.Response, out interface{}, log logger.Logger) error
2222
GetContentTypeHeader(method string, log logger.Logger) string
2323
GetAcceptHeader() string
2424
GetDefaultBaseDomain() string

apiintegrations/jamfpro/jamfpro_api_response.go

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,6 @@ func (j *JamfAPIHandler) HandleAPISuccessResponse(resp *http.Response, out inter
4141
return j.unmarshalResponse(contentType, bodyBytes, out)
4242
}
4343

44-
func (j *JamfAPIHandler) HandleAPIErrorResponse(resp *http.Response, out interface{}, log logger.Logger) error {
45-
// Read the response body
46-
bodyBytes, err := j.readResponseBody(resp)
47-
if err != nil {
48-
return err
49-
}
50-
51-
// Convert bodyBytes to a string to represent the raw response body
52-
rawResponse := string(bodyBytes)
53-
54-
// Log the raw response details for debugging
55-
j.logResponseDetails(resp, bodyBytes)
56-
57-
// Get the content type from the response headers
58-
contentType := resp.Header.Get("Content-Type")
59-
60-
// Handle known error content types (e.g., JSON, HTML)
61-
if strings.Contains(contentType, "application/json") {
62-
return j.handleErrorJSONResponse(bodyBytes, resp.StatusCode, rawResponse)
63-
} else if strings.Contains(contentType, "text/html") {
64-
return j.handleErrorHTMLResponse(bodyBytes, resp.StatusCode)
65-
}
66-
67-
// Generic error handling for unknown content types
68-
j.Logger.Error("Received non-success status code without detailed error response",
69-
zap.Int("status_code", resp.StatusCode),
70-
zap.String("raw_response", rawResponse),
71-
)
72-
return fmt.Errorf("received non-success status code: %d, raw response: %s", resp.StatusCode, rawResponse)
73-
}
74-
7544
// handleDeleteRequest handles the special case for DELETE requests, where a successful response might not contain a body.
7645
func (j *JamfAPIHandler) handleDeleteRequest(resp *http.Response) error {
7746
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
@@ -124,40 +93,71 @@ func (j *JamfAPIHandler) handleBinaryData(contentType, contentDisposition string
12493
return nil // If not binary data, no action needed
12594
}
12695

96+
// func (j *JamfAPIHandler) HandleAPIErrorResponse(resp *http.Response, out interface{}, log logger.Logger) error {
97+
// // Read the response body
98+
// bodyBytes, err := j.readResponseBody(resp)
99+
// if err != nil {
100+
// return err
101+
// }
102+
103+
// // Convert bodyBytes to a string to represent the raw response body
104+
// rawResponse := string(bodyBytes)
105+
106+
// // Log the raw response details for debugging
107+
// j.logResponseDetails(resp, bodyBytes)
108+
109+
// // Get the content type from the response headers
110+
// contentType := resp.Header.Get("Content-Type")
111+
112+
// // Handle known error content types (e.g., JSON, HTML)
113+
// if strings.Contains(contentType, "application/json") {
114+
// return j.handleErrorJSONResponse(bodyBytes, resp.StatusCode, rawResponse)
115+
// } else if strings.Contains(contentType, "text/html") {
116+
// return j.handleErrorHTMLResponse(bodyBytes, resp.StatusCode)
117+
// }
118+
119+
// // Generic error handling for unknown content types
120+
// j.Logger.Error("Received non-success status code without detailed error response",
121+
// zap.Int("status_code", resp.StatusCode),
122+
// zap.String("raw_response", rawResponse),
123+
// )
124+
// return fmt.Errorf("received non-success status code: %d, raw response: %s", resp.StatusCode, rawResponse)
125+
// }
126+
127127
// handleErrorHTMLResponse handles error responses with HTML content by extracting and logging the error message.
128-
func (j *JamfAPIHandler) handleErrorHTMLResponse(bodyBytes []byte, statusCode int) error {
129-
// Extract the error message from the HTML content
130-
htmlErrorMessage := ExtractErrorMessageFromHTML(string(bodyBytes))
131-
// Log the error message along with the status code
132-
j.Logger.Error("Received HTML error content",
133-
zap.String("error_message", htmlErrorMessage),
134-
zap.Int("status_code", statusCode),
135-
)
136-
// Return an error with the extracted message
137-
return fmt.Errorf("received HTML error content: %s", htmlErrorMessage)
138-
}
128+
// func (j *JamfAPIHandler) handleErrorHTMLResponse(bodyBytes []byte, statusCode int) error {
129+
// // Extract the error message from the HTML content
130+
// htmlErrorMessage := ExtractErrorMessageFromHTML(string(bodyBytes))
131+
// // Log the error message along with the status code
132+
// j.Logger.Error("Received HTML error content",
133+
// zap.String("error_message", htmlErrorMessage),
134+
// zap.Int("status_code", statusCode),
135+
// )
136+
// // Return an error with the extracted message
137+
// return fmt.Errorf("received HTML error content: %s", htmlErrorMessage)
138+
// }
139139

140140
// handleErrorJSONResponse handles error responses with JSON content by parsing the error message and logging it.
141-
func (j *JamfAPIHandler) handleErrorJSONResponse(bodyBytes []byte, statusCode int, rawResponse string) error {
142-
// Parse the JSON error response to extract the error description
143-
description, err := ParseJSONErrorResponse(bodyBytes)
144-
if err != nil {
145-
// Log the parsing error
146-
j.Logger.Error("Failed to parse JSON error response",
147-
zap.Error(err),
148-
zap.Int("status_code", statusCode),
149-
zap.String("raw_response", rawResponse), // Include raw response in the log
150-
)
151-
return fmt.Errorf("failed to parse JSON error response: %v, raw response: %s", err, rawResponse)
152-
}
153-
// Log the error description along with the status code and raw response
154-
j.Logger.Error("Received non-success status code with JSON response",
155-
zap.Int("status_code", statusCode),
156-
zap.String("error_description", description),
157-
zap.String("raw_response", rawResponse), // Include raw response in the log
158-
)
159-
return fmt.Errorf("received non-success status code with JSON response: %s, raw response: %s", description, rawResponse)
160-
}
141+
// func (j *JamfAPIHandler) handleErrorJSONResponse(bodyBytes []byte, statusCode int, rawResponse string) error {
142+
// // Parse the JSON error response to extract the error description
143+
// description, err := ParseJSONErrorResponse(bodyBytes)
144+
// if err != nil {
145+
// // Log the parsing error
146+
// j.Logger.Error("Failed to parse JSON error response",
147+
// zap.Error(err),
148+
// zap.Int("status_code", statusCode),
149+
// zap.String("raw_response", rawResponse), // Include raw response in the log
150+
// )
151+
// return fmt.Errorf("failed to parse JSON error response: %v, raw response: %s", err, rawResponse)
152+
// }
153+
// // Log the error description along with the status code and raw response
154+
// j.Logger.Error("Received non-success status code with JSON response",
155+
// zap.Int("status_code", statusCode),
156+
// zap.String("error_description", description),
157+
// zap.String("raw_response", rawResponse), // Include raw response in the log
158+
// )
159+
// return fmt.Errorf("received non-success status code with JSON response: %s, raw response: %s", description, rawResponse)
160+
// }
161161

162162
// unmarshalResponse unmarshals the response body into the provided output structure based on the content type (JSON or XML).
163163
func (j *JamfAPIHandler) unmarshalResponse(contentType string, bodyBytes []byte, out interface{}) error {

httpclient/multipartrequest.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/deploymenttheory/go-api-http-client/authenticationhandler"
99
"github.com/deploymenttheory/go-api-http-client/headers"
10+
"github.com/deploymenttheory/go-api-http-client/response"
1011
)
1112

1213
// DoMultipartRequest creates and executes a multipart HTTP request. It is used for sending files
@@ -86,7 +87,7 @@ func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]s
8687
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
8788
// Handle error responses
8889
//return nil, c.handleErrorResponse(resp, log, "Failed to process the HTTP request", method, endpoint)
89-
return nil, c.handleErrorResponse(resp, out, log, method, endpoint)
90+
return nil, response.HandleAPIErrorResponse(resp, log)
9091
} else {
9192
// Handle successful responses
9293
return resp, c.handleSuccessResponse(resp, out, log, method, endpoint)

httpclient/request.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -400,22 +400,22 @@ func (c *Client) do(req *http.Request, log logger.Logger, method, endpoint strin
400400
//
401401
// Returns:
402402
// - An error object parsed from the HTTP response, indicating the nature of the failure.
403-
func (c *Client) handleErrorResponse(resp *http.Response, out interface{}, log logger.Logger, method, endpoint string) error {
404-
if err := c.APIHandler.HandleAPIErrorResponse(resp, out, log); err != nil {
405-
log.Error("Failed to unmarshal HTTP response",
406-
zap.String("method", method),
407-
zap.String("endpoint", endpoint),
408-
zap.Error(err),
409-
)
410-
return err
411-
}
412-
log.Info("HTTP request succeeded",
413-
zap.String("method", method),
414-
zap.String("endpoint", endpoint),
415-
zap.Int("status_code", resp.StatusCode),
416-
)
417-
return nil
418-
}
403+
// func (c *Client) handleErrorResponse(resp *http.Response, out interface{}, log logger.Logger, method, endpoint string) error {
404+
// if err := c.APIHandler.HandleAPIErrorResponse(resp, out, log); err != nil {
405+
// log.Error("Failed to unmarshal HTTP response",
406+
// zap.String("method", method),
407+
// zap.String("endpoint", endpoint),
408+
// zap.Error(err),
409+
// )
410+
// return err
411+
// }
412+
// log.Info("HTTP request succeeded",
413+
// zap.String("method", method),
414+
// zap.String("endpoint", endpoint),
415+
// zap.Int("status_code", resp.StatusCode),
416+
// )
417+
// return nil
418+
// }
419419

420420
// handleSuccessResponse unmarshals a successful HTTP response into the provided output parameter and logs the
421421
// success details. It's designed for use when the response indicates success (status code within 200-299).

response/error.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,20 @@ func parseHTMLResponse(bodyBytes []byte, apiError *APIError, log logger.Logger,
170170
var parse func(*html.Node)
171171
parse = func(n *html.Node) {
172172
if n.Type == html.ElementNode && n.Data == "p" {
173+
var pText strings.Builder
173174
for c := n.FirstChild; c != nil; c = c.NextSibling {
174-
if c.Type == html.TextNode {
175-
// Accumulate text content of <p> tag
176-
messages = append(messages, c.Data)
175+
if c.Type == html.TextNode && strings.TrimSpace(c.Data) != "" {
176+
// Build text content of <p> tag
177+
if pText.Len() > 0 {
178+
pText.WriteString(" ") // Add a space between text nodes within the same <p> tag
179+
}
180+
pText.WriteString(strings.TrimSpace(c.Data))
177181
}
178182
}
183+
if pText.Len() > 0 {
184+
// Add the built text content of the <p> tag to messages
185+
messages = append(messages, pText.String())
186+
}
179187
}
180188
for c := n.FirstChild; c != nil; c = c.NextSibling {
181189
parse(c) // Recursively parse the document

0 commit comments

Comments
 (0)