req-http-client
Req HTTP Client
Examples use base_url / url variables or https://api.example.com as placeholders only — never commit real host secrets.
Canonical FP bar: docs/fcis-engineering-rules.md — Functional Core, Imperative Shell: pure domain modules; side effects at edges. HTTP/email/i18n adapters are edges; keep request building and response mapping pure where possible.
Sections: RULES · End-to-End Workflow · Quick-Reference: Request Types · Retries · Streaming Responses · Common Pitfalls · Integration
RULES — Follow these with no exceptions
1. Always build a configured base client with Req.new/1 — set base_url, receive_timeout, and default headers once, then reuse it for every call instead of re-passing options
2. Use the non-bang Req.get/1 / Req.post/1 in application code — pattern match {:ok, %{status: _, body: _}} / {:error, _}; reserve the ! variants for scripts and tests
3. Match status codes explicitly — handle 404, 429, and status >= 500 distinctly; never collapse every non-200 into one branch
4. Enable retry: :transient only for idempotent requests — Req retries 5xx and network errors with backoff; never blindly retry non-idempotent writes
5. Set an explicit receive_timeout — never rely on infinite defaults for calls to external services
6. Stub every external call in tests with Req.Test — the suite must never hit a real API
7. Stream large responses with into: — write to File.stream!/1 or a callback instead of loading the full payload into memory
See assets/req_client_snippets.ex for a copy-paste base client and wrapper module.