Skip to content

Instantly share code, notes, and snippets.

@minitauros
Last active July 26, 2022 09:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minitauros/cad602b290d59b39658cd855a663fd5c to your computer and use it in GitHub Desktop.
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.
// 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