Last active
July 26, 2022 09:30
-
-
Save minitauros/cad602b290d59b39658cd855a663fd5c to your computer and use it in GitHub Desktop.
Decode a JSON response while also adding the JSON response body to the unmarshalling error.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DecodeJSONResp decodes the body of the given response into the given target. | |
// If an error occurs, instead of only returning the unmarshaling error, the error will also contain the first 100 chars | |
// of the response JSON. This allows for better debugging. | |
func DecodeJSONResp(resp *http.Response, target interface{}) error { | |
pr, pw := io.Pipe() | |
tr := io.TeeReader(resp.Body, pw) | |
respCh := make(chan string) | |
errCh := make(chan error) | |
go func() { | |
firstChars := make([]byte, 100) | |
defer func() { | |
_ = pr.Close() | |
respCh <- string(firstChars) | |
close(errCh) | |
}() | |
_, err := io.ReadFull(pr, firstChars) | |
if err == io.EOF || err == io.ErrUnexpectedEOF { | |
return | |
} else if err != nil { | |
errCh <- err | |
return | |
} | |
// Discard the rest; we are only interested in the first x chars. | |
_, err = io.Copy(io.Discard, pr) | |
if err != nil { | |
errCh <- err | |
return | |
} | |
}() | |
var err error | |
decoder := json.NewDecoder(tr) | |
for { | |
err = decoder.Decode(target) | |
if err != nil { | |
break | |
} | |
} | |
_ = pw.Close() | |
firstChars := <-respCh | |
if err != io.EOF { | |
err2 := <-errCh | |
if err2 != nil { | |
return errors.Errorf("url '%s': %v (response reading error: %v, response body starting with '%s')", resp.Request.URL.String(), err, err2, firstChars) | |
} | |
return errors.Errorf("url '%s': %v (response body starting with '%s')", resp.Request.URL.String(), err, firstChars) | |
} | |
if resp.StatusCode >= 300 { | |
return errors.Errorf("url '%s': response status was %d; body was %s", resp.Request.URL.String(), resp.StatusCode, firstChars) | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment