MDN Fetch API - discussion (2023-05-13)
The MDN Fetch API docs are deceptively "basic"—most of the tricky production issues come down to request identity, abort semantics, and what you assume about responses. I'm curious how people incorporate fetch semantics into an app that wants observable posture (lane + evidence) rather than "it failed somewhere".
Do you normalize fetch outcomes into a shared lane contract, or let each surface interpret Response? How do you handle abort/races so stale responses don't win? Do you treat caching as a fetch concern or a route-shell concern (choose a cache lane at the shell)?
Comments (14)
Back to latestNormalize into a lane contract.
If you don't, each component invents its own error model.
We log aborts as normal behavior, not as errors:
txt
[tips] fetch start key=/api/search?q=react reason=query:commit
[tips] fetch abort key=/api/search?q=react reason=query:changed
[tips] fetch start key=/api/search?q=react+router reason=query:commit
Once you narrate aborts, race conditions stop looking like random flakiness.
We treat caching as a shell concern because the shell can see track posture.
Fetch wrappers should expose hooks for identity/abort, but the decision of cache lane (fast/proof/etc) is product policy.
Concrete alternative: never wrap fetch, always use raw fetch and handle errors per feature.
We tried that. It looked flexible until we needed to change error messaging across the app. Normalization at a boundary was the only way to make behavior consistent.
Same. The wrapper isn't about hiding fetch, it's about publishing a stable contract surface.
If you need flexibility, make the wrapper accept a policy input (lane/ttl), not custom per-component behavior.
Docs tie-in: the render-time fetch primitives in the docs pair well with MDN semantics when you keep identity explicit.
Related: Data Fetching and Caching and Error Handling.
Long-form: request identity is the real API.
If you compute identity from raw URL strings, you get cache fragmentation (ordering differences, encoding differences). Normalize first, then compute key, then fetch.
We also render evidence for key + lane so support can say "I was on proof lane" instead of "it was slow".
Streaming is where fetch semantics matter most.
You have to decide what posture partial data is.
We treat 204/empty bodies as a first-class case in the wrapper. Otherwise every endpoint surprises you.
MDN is helpful here because it reminds you how much behavior is in Response.
We had a bug where aborted requests were reported as errors in UI.
Fix was: abort maps to a distinct lane/evidence token (lane=idle reason=abort) instead of error.
If you want to keep this debuggable, log start/resolve/reject as one-line tips logs and keep them stable.
Otherwise you'll never correlate a user report with what actually happened.
Small detail: treat timeouts explicitly. fetch doesn't timeout by default.
We wrap timeouts as evidence tokens so UI can distinguish offline vs slow server vs abort.
Long-form counterpoint: wrappers can become too smart and hide important behaviors.
The compromise for us is a thin wrapper that returns a calm lane shape but still exposes raw response metadata (status, headers) when needed for debugging.
Treat cache lane selection as product policy, not as a fetch helper detail.
Takeaway: read MDN, then decide your contract vocabulary: identity, posture, source, and abort behavior.
Once those are explicit, React integration becomes straightforward.