Files
go-kata/16-http-client-hygiene/README.md
2026-01-04 20:40:07 +01:00

49 lines
1.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kata 16: The HTTP Client Hygiene Wrapper
**Target Idioms:** `net/http` Transport Reuse, Timeouts, Context-First APIs, Response Body Draining
**Difficulty:** 🔴 Advanced
## 🧠 The "Why"
“Works locally” HTTP code in Go often fails in prod because people:
- use `http.DefaultClient` with no timeouts,
- create a new client/transport per request (connection churn),
- forget to close bodies (leaks + no keep-alive reuse),
- dont drain bodies (prevents connection reuse).
This kata is about building a small internal SDK the **Go way**.
## 🎯 The Scenario
Your service calls a downstream API that sometimes returns large error bodies and sometimes hangs.
You need:
- strict timeouts,
- proper cancellation,
- safe connection reuse,
- structured logs.
## 🛠 The Challenge
Implement:
- `type APIClient struct { ... }`
- `func (c *APIClient) GetJSON(ctx context.Context, url string, out any) error`
### 1. Functional Requirements
- [ ] Use `http.NewRequestWithContext`.
- [ ] Decode JSON on 2xx responses into `out`.
- [ ] On non-2xx: read up to N bytes of body and return an error including status code.
### 2. The "Idiomatic" Constraints (Pass/Fail Criteria)
- [ ] **Must NOT** use `http.DefaultClient`.
- [ ] **Must** configure timeouts (`Client.Timeout` and/or transport-level timeouts).
- [ ] **Must** reuse a single `Transport` (connection pooling).
- [ ] **Must** `defer resp.Body.Close()`.
- [ ] **Must** drain (at least partially) error bodies to allow connection reuse.
- [ ] Use `slog` with fields: method, url, status, latency.
## 🧪 Self-Correction (Test Yourself)
- **If connections spike under load:** you probably rebuild transports.
- **If keep-alives dont work:** you likely didnt drain/close body.
- **If hangs occur:** you likely lack correct timeout configuration.
## 📚 Resources
- https://go.dev/src/net/http/client.go
- https://go.dev/src/net/http/transport.go
- https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/