Golang / GoLang Production Patterns and Web Standards Interview Questions
What are the best practices for using Go's HTTP client in production?
The default http.DefaultClient is not suitable for production — it has no timeouts, uses a shared transport, and cannot be instrumented. Production code creates dedicated clients with explicit configuration.
// Production HTTP client â never use http.DefaultClient in libraries func newHTTPClient() *http.Client { return &http.Client{ Timeout: 30 * time.Second, // total request timeout including body read Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 10, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, // Keep-alive enabled by default DisableKeepAlives: false, }, } } // Reuse clients â they manage connection pools internally var apiClient = newHTTPClient() // Always use context for cancellation and timeout func callAPI(ctx context.Context, url string) ([]byte, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", "myservice/1.0") resp, err := apiClient.Do(req) if err != nil { return nil, fmt.Errorf("executing request: %w", err) } defer resp.Body.Close() // Always read and close body â even on error status body, err := io.ReadAll(io.LimitReader(resp.Body, 10<<20)) // 10 MB limit if err != nil { return nil, fmt.Errorf("reading body: %w", err) } if resp.StatusCode >= 400 { return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, body) } return body, nil } // RETRY with exponential backoff for idempotent requests func callWithRetry(ctx context.Context, url string, maxRetries int) ([]byte, error) { var lastErr error for attempt := 0; attempt < maxRetries; attempt++ { if attempt > 0 { delay := time.Duration(attempt*attempt) * 100 * time.Millisecond select { case <-time.After(delay): case <-ctx.Done(): return nil, ctx.Err() } } data, err := callAPI(ctx, url) if err == nil { return data, nil } lastErr = err } return nil, fmt.Errorf("after %d retries: %w", maxRetries, lastErr) }
More Related questions...