Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ module github.com/deploymenttheory/go-api-http-client
go 1.21

require (
github.com/antchfx/xmlquery v1.3.18
github.com/antchfx/xmlquery v1.4.0
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
golang.org/x/net v0.24.0
)

require (
github.com/antchfx/xpath v1.2.4 // indirect
github.com/antchfx/xpath v1.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/antchfx/xmlquery v1.3.18 h1:FSQ3wMuphnPPGJOFhvc+cRQ2CT/rUj4cyQXkJcjOwz0=
github.com/antchfx/xmlquery v1.3.18/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA=
github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY=
github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antchfx/xmlquery v1.4.0 h1:xg2HkfcRK2TeTbdb0m1jxCYnvsPaGY/oeZWTGqX/0hA=
github.com/antchfx/xmlquery v1.4.0/go.mod h1:Ax2aeaeDjfIw3CwXKDQ0GkwZ6QlxoChlIBP+mGnDFjI=
github.com/antchfx/xpath v1.3.0 h1:nTMlzGAK3IJ0bPpME2urTuFL76o4A96iYvoKFHRXJgc=
github.com/antchfx/xpath v1.3.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
Expand Down
39 changes: 19 additions & 20 deletions response/success.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,17 @@ func HandleAPISuccessResponse(resp *http.Response, out interface{}, log logger.L
return handleDeleteRequest(resp, log)
}

// Create a buffer to hold a copy of the response body
var bodyBuffer bytes.Buffer

// Use TeeReader to read the response body and simultaneously write it to the buffer
teeReader := io.TeeReader(resp.Body, &bodyBuffer)

// log the response body
logResponseDetails(resp, bodyBuffer.Bytes(), log)
// Log headers and set up deferred body logging.
deferBodyLog := logResponseDetails(resp, log)
defer deferBodyLog() // Ensure body logging happens at the end of this function.

mimeType, _ := ParseContentTypeHeader(resp.Header.Get("Content-Type"))
contentDisposition := resp.Header.Get("Content-Disposition")

if handler, ok := responseUnmarshallers[mimeType]; ok {
// Replace the response body with a new reader that reads from the buffer, allowing it to be read again
resp.Body = io.NopCloser(&bodyBuffer)
return handler(teeReader, out, log, mimeType) // Use teeReader here to unmarshal from the original response body
return handler(resp.Body, out, log, mimeType)
} else if isBinaryData(mimeType, contentDisposition) {
// Replace the response body with a new reader that reads from the buffer, allowing it to be read again
resp.Body = io.NopCloser(&bodyBuffer)
return handleBinaryData(teeReader, log, out, mimeType, contentDisposition) // Use teeReader here to handle binary data
return handleBinaryData(resp.Body, log, out, mimeType, contentDisposition)
} else {
errMsg := fmt.Sprintf("unexpected MIME type: %s", mimeType)
log.Error("Unmarshal error", zap.String("content type", mimeType), zap.Error(errors.New(errMsg)))
Expand All @@ -74,14 +65,22 @@ func handleDeleteRequest(resp *http.Response, log logger.Logger) error {
return fmt.Errorf("DELETE request failed, status code: %d", resp.StatusCode)
}

// Adjusted logResponseDetails to handle a potential nil bodyBytes.
func logResponseDetails(resp *http.Response, bodyBytes []byte, log logger.Logger) {
// Conditional logging if bodyBytes is not nil.
if bodyBytes != nil {
// logResponseDetails logs the raw response details and returns a deferred function to log the response body.
func logResponseDetails(resp *http.Response, log logger.Logger) func() {
log.Debug("HTTP Response Headers", zap.Any("Headers", resp.Header))

// Returning a deferred function to log the body.
return func() {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Error("Error reading response body for logging", zap.Error(err))

Check warning

Code scanning / gosec

Errors unhandled.

Errors unhandled.
return
}
log.Debug("Raw HTTP Response", zap.String("Body", string(bodyBytes)))

// After logging, reset resp.Body so it can be read again.
resp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
// Logging headers remains unchanged.
log.Debug("HTTP Response Headers", zap.Any("Headers", resp.Header))
}

// unmarshalJSON unmarshals JSON content from an io.Reader into the provided output structure.
Expand Down