GetJSON HTTP helper with timeout and status checks

Go
package fetch

import (
    "context"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

// GetJSON fetches rawurl with a 10s timeout and decodes JSON into out; client must be non-nil.
func GetJSON(ctx context.Context, client *http.Client, rawurl string, out any) error {
    ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
    defer cancel()

    req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawurl, nil)
    if err != nil {
        return fmt.Errorf("new request: %w", err)
    }
    req.Header.Set("Accept", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        return fmt.Errorf("get %s: %w", rawurl, err)
    }
    defer resp.Body.Close()

    if resp.StatusCode < 200 || resp.StatusCode > 299 {
        msg, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
        return fmt.Errorf("get %s: status %d: %s", rawurl, resp.StatusCode, msg)
    }
    if err := json.NewDecoder(resp.Body).Decode(out); err != nil {
        return fmt.Errorf("decode %s: %w", rawurl, err)
    }
    return nil
}