···11+# HTTP Client
22+33+> Fetching data with retry and timeout shouldn't require 50 lines of boilerplate.
44+55+## The Problem
66+77+Every app fetches data from APIs. Simple, right? But production code needs:
88+- **Retry logic** for transient failures
99+- **Timeouts** so requests don't hang forever
1010+- **Proper cleanup** when requests are cancelled
1111+- **Typed errors** so you know what can go wrong
1212+1313+In vanilla TypeScript, this turns into a mess of nested try/catch, manual AbortController management, and `catch (e: unknown)` everywhere.
1414+1515+## Run Both Versions
1616+1717+```bash
1818+bun run examples/http-client/without-purus.ts
1919+bun run examples/http-client/with-purus.ts
2020+```
2121+2222+## Without purus
2323+2424+See `without-purus.ts` - realistic code showing:
2525+- Manual AbortController + setTimeout coordination
2626+- Easy to forget `clearTimeout` in error paths (memory leak!)
2727+- `catch (e: unknown)` - no idea what errors can happen
2828+- Retry logic scattered with exponential backoff math
2929+- No way to cancel a request from outside
3030+3131+## With purus
3232+3333+See `with-purus.ts` - same functionality with:
3434+- `pipe(fetch, retry(3), timeout(5000))` - composable one-liner
3535+- Typed `HttpError` union - compiler knows all error cases
3636+- Automatic cleanup on fiber interrupt
3737+- Clear, readable data flow
3838+3939+## Key Takeaways
4040+4141+- **Typed errors** -> No more `catch (e: unknown)` guessing games
4242+- **Automatic cleanup** -> Can't forget to clear timeouts
4343+- **Composable combinators** -> `retry` and `timeout` are just functions
4444+- **Cancellation propagates** -> Interrupt a fiber, cleanup runs automatically