Unmarshal JSON from HTTP request in Go
Use json.Unmarshal instead of json.Decoder, or a thin HTTP client library.
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)
}