go 55 lines · 8 steps

Concurrent API fetches with errgroup in Go

Fetch a user, their repos, and orgs in parallel, cancelling the rest the moment any request fails.

Explained by highlit
1package fetch
2 
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 
9 "golang.org/x/sync/errgroup"
10)
11 
12type Profile struct {
13 User User
14 Repos []Repo
15 Orgs []Org
16}
17 
18func LoadProfile(ctx context.Context, client *http.Client, username string) (*Profile, error) {
19 g, ctx := errgroup.WithContext(ctx)
20 var profile Profile
21 
22 g.Go(func() error {
23 return getJSON(ctx, client, "/users/"+username, &profile.User)
24 })
25 
26 g.Go(func() error {
27 return getJSON(ctx, client, "/users/"+username+"/repos", &profile.Repos)
28 })
29 
30 g.Go(func() error {
31 return getJSON(ctx, client, "/users/"+username+"/orgs", &profile.Orgs)
32 })
33 
34 if err := g.Wait(); err != nil {
35 return nil, fmt.Errorf("load profile %q: %w", username, err)
36 }
37 return &profile, nil
38}
39 
40func getJSON(ctx context.Context, client *http.Client, path string, dst any) error {
41 req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com"+path, nil)
42 if err != nil {
43 return err
44 }
45 resp, err := client.Do(req)
46 if err != nil {
47 return err
48 }
49 defer resp.Body.Close()
50 
51 if resp.StatusCode != http.StatusOK {
52 return fmt.Errorf("%s: unexpected status %s", path, resp.Status)
53 }
54 return json.NewDecoder(resp.Body).Decode(dst)
55}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1errgroup.WithContext ties a set of goroutines to one context that cancels as soon as any of them returns an error.
  2. 2Each goroutine writing to a distinct field of a shared struct avoids data races without explicit locking.
  3. 3Wrapping the aggregated error with %w preserves the underlying cause for callers to inspect.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Concurrent API fetches with errgroup in Go — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code