HTTP Client
Never use the default http.Get in production
http.Get(url) uses the default client which has no timeout. A slow server can hang your goroutine forever:
Always create a client with an explicit timeout:
Always close the response body
An unclosed response body holds a TCP connection in the pool. Always defer resp.Body.Close() immediately after checking the error.
Checking status codes
The HTTP client does not return an error for 4xx/5xx responses โ only network errors:
Check resp.StatusCode explicitly after every request.
Building a request manually
client.Do(req) gives full control over method, headers, and body:
Always prefer http.NewRequestWithContext over http.NewRequest so the request respects context cancellation.
Reading JSON responses
json.NewDecoder reads directly from the response body without buffering the entire payload โ important for large responses.
Custom transport for connection pooling
Create the client once at startup (package-level or in a struct) and reuse it. Creating a new http.Client per request bypasses connection pooling.
Retries with exponential backoff
For transient failures (5xx, network errors), retry with backoff:
Knowledge Check
Why should you always create `http.Client{Timeout: ...}` rather than using `http.Get` directly?
What happens if you forget to call `resp.Body.Close()`?
Why use http.NewRequestWithContext instead of http.NewRequest?