Skip to content

Commit 6761fbd

Browse files
committed
Add error handling and logging for HTTP responses
1 parent 97fe973 commit 6761fbd

File tree

1 file changed

+62
-98
lines changed

1 file changed

+62
-98
lines changed

httpclient/httpclient_request.go

Lines changed: 62 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,61 @@ func (c *Client) executeHTTPRequest(req *http.Request, log logger.Logger, method
5050
return resp, nil
5151
}
5252

53+
// handleErrorResponse processes and logs errors from an HTTP response, allowing for a customizable error message.
54+
//
55+
// Parameters:
56+
// - resp: The *http.Response received from the server.
57+
// - log: An instance of a logger (conforming to the logger.Logger interface) for logging the error details.
58+
// - errorMessage: A custom error message that provides context about the error.
59+
// - method: The HTTP method used for the request, for logging purposes.
60+
// - endpoint: The endpoint the request was sent to, for logging purposes.
61+
//
62+
// Returns:
63+
// - An error object parsed from the HTTP response, indicating the nature of the failure.
64+
func (c *Client) handleErrorResponse(resp *http.Response, log logger.Logger, errorMessage, method, endpoint string) error {
65+
apiErr := errors.HandleAPIError(resp, log)
66+
67+
// Log the provided error message along with method, endpoint, and status code.
68+
log.Error(errorMessage,
69+
zap.String("method", method),
70+
zap.String("endpoint", endpoint),
71+
zap.Int("status_code", resp.StatusCode),
72+
zap.String("error", apiErr.Error()),
73+
)
74+
75+
return apiErr
76+
}
77+
78+
// handleSuccessResponse unmarshals a successful HTTP response into the provided output parameter and logs the
79+
// success details. It's designed for use when the response indicates success (status code within 200-299).
80+
// The function logs the request's success and, in case of unmarshalling errors, logs the failure and returns the error.
81+
//
82+
// Parameters:
83+
// - resp: The *http.Response received from the server.
84+
// - out: A pointer to the variable where the unmarshalled response will be stored.
85+
// - log: An instance of a logger (conforming to the logger.Logger interface) for logging success or unmarshalling errors.
86+
// - method: The HTTP method used for the request, for logging purposes.
87+
// - endpoint: The endpoint the request was sent to, for logging purposes.
88+
//
89+
// Returns:
90+
// - nil if the response was successfully unmarshalled into the 'out' parameter, or an error if unmarshalling failed.
91+
func (c *Client) handleSuccessResponse(resp *http.Response, out interface{}, log logger.Logger, method, endpoint string) error {
92+
if err := c.APIHandler.UnmarshalResponse(resp, out, log); err != nil {
93+
log.Error("Failed to unmarshal HTTP response",
94+
zap.String("method", method),
95+
zap.String("endpoint", endpoint),
96+
zap.Error(err),
97+
)
98+
return err
99+
}
100+
log.Info("HTTP request succeeded",
101+
zap.String("method", method),
102+
zap.String("endpoint", endpoint),
103+
zap.Int("status_code", resp.StatusCode),
104+
)
105+
return nil
106+
}
107+
53108
// DoRequest constructs and executes a standard HTTP request with support for retry logic.
54109
// It is intended for operations that can be encoded in a single JSON or XML body such as
55110
// creating or updating resources. This method includes token validation, concurrency control,
@@ -87,26 +142,6 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
87142
if err != nil || !valid {
88143
return nil, fmt.Errorf("validity of the authentication token failed with error: %w", err)
89144
}
90-
/*
91-
// Acquire a token for concurrency management with a timeout and measure its acquisition time
92-
tokenAcquisitionStart := time.Now()
93-
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
94-
defer cancel()
95-
96-
requestID, err := c.ConcurrencyMgr.Acquire(ctx)
97-
if err != nil {
98-
return nil, err
99-
}
100-
defer c.ConcurrencyMgr.Release(requestID)
101-
102-
tokenAcquisitionDuration := time.Since(tokenAcquisitionStart)
103-
c.PerfMetrics.lock.Lock()
104-
c.PerfMetrics.TokenWaitTime += tokenAcquisitionDuration
105-
c.PerfMetrics.lock.Unlock()
106-
107-
// Add the request ID to the context
108-
ctx = context.WithValue(ctx, requestIDKey{}, requestID)
109-
*/
110145

111146
// Acquire a token for concurrency management
112147
ctx, err := c.AcquireConcurrencyToken(context.Background(), log)
@@ -168,19 +203,6 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
168203
// Start response time measurement
169204
responseTimeStart := time.Now()
170205

171-
// Execute the request
172-
/*
173-
resp, err := c.httpClient.Do(req)
174-
if err != nil {
175-
log.Error("Failed to send retryable request",
176-
zap.String("method", method),
177-
zap.String("endpoint", endpoint),
178-
zap.Int("status_code", resp.StatusCode),
179-
zap.String("status_text", http.StatusText(resp.StatusCode)),
180-
)
181-
return nil, err
182-
}*/
183-
184206
// Execute the request
185207
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
186208
if err != nil {
@@ -190,12 +212,7 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
190212
// After each request, compute and update response time
191213
responseDuration := time.Since(responseTimeStart)
192214
c.updatePerformanceMetrics(responseDuration)
193-
/*
194-
responseDuration := time.Since(responseTimeStart)
195-
c.PerfMetrics.lock.Lock()
196-
c.PerfMetrics.TotalResponseTime += responseDuration
197-
c.PerfMetrics.lock.Unlock()
198-
*/
215+
199216
// Checks for the presence of a deprecation header in the HTTP response and logs if found.
200217
if i == 0 {
201218
CheckDeprecationHeader(resp, log)
@@ -293,35 +310,16 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
293310
// For non-retryable HTTP Methods (POST - Create)
294311
req = req.WithContext(ctx)
295312

296-
// Execute the request
297-
/*
298-
resp, err := c.httpClient.Do(req)
299-
if err != nil {
300-
log.Error("Failed to send request",
301-
zap.String("method", method),
302-
zap.String("endpoint", endpoint),
303-
zap.Int("status_code", resp.StatusCode),
304-
zap.String("status_text", http.StatusText(resp.StatusCode)),
305-
)
306-
return nil, err
307-
}
308-
*/
309313
// Execute the request
310314
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
311315
if err != nil {
312316
return nil, err
313317
}
318+
314319
// After each request, compute and update response time
315320
responseDuration := time.Since(responseTimeStart)
316321
c.updatePerformanceMetrics(responseDuration)
317322

318-
/*
319-
responseDuration := time.Since(responseTimeStart)
320-
c.PerfMetrics.lock.Lock()
321-
c.PerfMetrics.TotalResponseTime += responseDuration
322-
c.PerfMetrics.lock.Unlock()
323-
*/
324-
325323
// Checks for the presence of a deprecation header in the HTTP response and logs if found.
326324
CheckDeprecationHeader(resp, log)
327325

@@ -431,20 +429,6 @@ func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]s
431429
// Set Request Headers
432430
c.SetRequestHeaders(req, contentType, acceptHeader, log)
433431

434-
// Execute the request
435-
/*
436-
resp, err := c.httpClient.Do(req)
437-
if err != nil {
438-
log.Error("Failed to send multipart request",
439-
zap.String("method", method),
440-
zap.String("endpoint", endpoint),
441-
zap.Int("status_code", resp.StatusCode),
442-
zap.String("status_text", http.StatusText(resp.StatusCode)),
443-
)
444-
return nil, err
445-
}
446-
*/
447-
448432
// Execute the request
449433
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
450434
if err != nil {
@@ -453,30 +437,10 @@ func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]s
453437

454438
// Check for successful status code
455439
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
456-
// Use HandleAPIError to process the error response and log it accordingly
457-
apiErr := errors.HandleAPIError(resp, log)
458-
459-
// Log additional context about the request that led to the error
460-
log.Error("Received non-success status code from multipart request",
461-
zap.String("method", method),
462-
zap.String("endpoint", endpoint),
463-
zap.Int("status_code", resp.StatusCode),
464-
zap.String("status_text", http.StatusText(resp.StatusCode)),
465-
)
466-
467-
// Return the original HTTP response and the API error
468-
return resp, apiErr
440+
// Handle error responses
441+
return nil, c.handleErrorResponse(resp, log, "Failed to process the HTTP request", method, endpoint)
442+
} else {
443+
// Handle successful responses
444+
return resp, c.handleSuccessResponse(resp, out, log, method, endpoint)
469445
}
470-
471-
// Unmarshal the response
472-
if err := apiHandler.UnmarshalResponse(resp, out, log); err != nil {
473-
log.Error("Failed to unmarshal HTTP response",
474-
zap.String("method", method),
475-
zap.String("endpoint", endpoint),
476-
zap.String("error", err.Error()),
477-
)
478-
return resp, err
479-
}
480-
481-
return resp, nil
482446
}

0 commit comments

Comments
 (0)