Unmarshal JSON from HTTP request in Go

Use json.Unmarshal instead of json.Decoder, or a thin HTTP client library.

Unmarshal JSON from HTTP request in Go
Photo by Joni Ludlow / Unsplash

Instead of using json.Decoder:

var user User
resp, _ := client.Do(req)
_ = json.NewDecoder(resp.Body).Decode(&user)

In most cases you actually want to json.Unmarshal:

var user User
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
_ = json.Unmarshal(body, &user)

The rationale being that json.Decoder is meant to decode multiple successive payloads from the reader, so it won't be pedantic about bad data after the first json document.

In order to further reduce the boilerplate and error handling, a thin http client library may be helpful, especially if you do a lot of calls. For example, carlmjohnson/requests.

With standard library best practices (context, custom HTTP client):

var user User

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
  return fmt.Errorf("building request: %w", err)
}

resp, err := client.Do(req)
if err != nil {
  return fmt.Errorf("sending request: %w", err)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
  return fmt.Errorf("reading body: %w", err)
}

err = json.Unmarshal(body, &user)
if err != nil {
  return fmt.Errorf("unmarshalling json: %w", err)
}

With carlmjohnson/requests:

var user User

err := requests.URL(url).ToJSON(&user).Client(client).Fetch(ctx)
if err != nil {
  return fmt.Errorf("fetching user: %w", err)
}

đź“š Further reading

encoding/json/v2 · golang go · Discussion #63397
This is a discussion intended to lead to a formal proposal. This was written with input from @mvdan, @johanbrandhorst, @rogpeppe, @chrishines, @rsc. Background The widely-used “encoding/json” packa…
encoding/json: the Decoder.Decode API lends itself to misuse · Issue #36225 · golang/go
I’m observing the existence of several production servers that are buggy because the json.Decoder.Decode API lends itself to misuse. Consider the following: r := strings.NewReader(”{} bad data”) va…