← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Fetch API & HTTP Requests

javascript ES2015 Beginner
debt(d7/e1/b3/t9)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). ESLint can flag bare fetch() calls but detecting the missing response.ok check is a nuanced pattern that requires either a custom ESLint rule or careful code review. TypeScript alone won't catch it since fetch() resolves with a Response object regardless of HTTP status. The detection_hints confirm eslint and typescript as tools, but the specific anti-pattern (not checking response.ok) is not caught by default rules — it takes specialist configuration or review.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1). The quick_fix confirms this: add a response.ok check and throw manually after the fetch call, or add AbortController. These are localized, single-site additions at each fetch() call site. No architectural rework required.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to context is web only, and the burden falls at each fetch() call site. It imposes a recurring but localized discipline (always check response.ok, always handle AbortController) without reshaping the wider codebase architecture.

t9 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'catastrophic trap — the obvious way is always wrong' (t9). The misconception field states exactly this: developers universally expect a Promise-based HTTP client to reject on 4xx/5xx errors — the same mental model they bring from axios, jQuery AJAX, or most HTTP libraries. fetch() silently resolves instead. The obvious code path (catch block handles errors) misses every HTTP-level error. This is the canonical t9 trap.

About DEBT scoring →

Also Known As

Fetch API window.fetch browser fetch

TL;DR

The modern browser API for HTTP requests — Promise-based, streaming-capable, and replacing XMLHttpRequest in all new code.

Explanation

fetch(url, options) returns a Promise resolving to a Response object. Unlike XMLHttpRequest, fetch doesn't reject on HTTP error status codes (404, 500) — only on network failure. Always check response.ok or response.status: if(!res.ok) throw new Error(res.status). Response body is consumed once via streaming methods: res.json(), res.text(), res.blob(), res.arrayBuffer(). Options: method, headers, body (JSON.stringify(data)), credentials ('include' for cookies), signal (AbortController for cancellation). The AbortController pattern enables timeout handling: const controller = new AbortController(); setTimeout(() => controller.abort(), 5000). In Node.js, fetch is available natively from v18.

Diagram

sequenceDiagram
    participant JS as JavaScript
    participant FETCH as Fetch API
    participant SERVER as Server
    JS->>FETCH: fetch url options
    Note over FETCH: Returns Promise immediately
    FETCH->>SERVER: HTTP Request
    SERVER-->>FETCH: HTTP Response
    FETCH-->>JS: Response object Promise
    JS->>FETCH: response.json()
    FETCH-->>JS: Parsed data Promise
    Note over JS: Error handling
    JS->>FETCH: fetch bad-url
    FETCH-->>JS: Rejects on network error
    Note over JS: 404 500 do NOT reject<br/>check response.ok

Common Misconception

fetch() rejects the Promise on HTTP error responses like 404 or 500. fetch() only rejects on network failures. HTTP 4xx and 5xx responses resolve the Promise successfully — you must check response.ok or response.status explicitly to detect HTTP-level errors.

Why It Matters

The Fetch API replaces XMLHttpRequest with a Promise-based interface — but its error handling is non-obvious: fetch only rejects on network failure, not on 4xx/5xx HTTP status codes.

Common Mistakes

  • Not checking response.ok — fetch resolves (not rejects) for 404 and 500 responses.
  • Not handling network errors separately from HTTP errors — both need different user feedback.
  • Not setting Content-Type header for POST requests with JSON body.
  • Not aborting fetch requests with AbortController when the component unmounts.

Code Examples

✗ Vulnerable
// fetch resolves on 404 — error silently ignored:
fetch('/api/user/999')
    .then(res => res.json())
    .then(data => console.log(data)); // data is {error: 'Not found'} — not thrown!

// Correct:
fetch('/api/user/999')
    .then(res => { if (!res.ok) throw new Error(res.status); return res.json(); })
    .then(data => console.log(data))
    .catch(err => console.error(err));
✓ Fixed
const res = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Alice' }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const user = await res.json();

Added 15 Mar 2026
Edited 22 Mar 2026
Views 40
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 1 ping T 0 pings W 1 ping T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F
Perplexity 1
No pings yesterday
Perplexity 11 Amazonbot 7 ChatGPT 4 Unknown AI 3 Google 2 Ahrefs 2 SEMrush 2 Majestic 1 Qwen 1
crawler 32 crawler_json 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
fetch() does not reject on HTTP errors (4xx/5xx) — always check response.ok and throw manually; add AbortController for timeouts and cancellation
📦 Applies To
javascript ES2015 web
🔗 Prerequisites
🔍 Detection Hints
fetch() without checking response.ok; no AbortController timeout; credentials not configured for cross-origin
Auto-detectable: ✓ Yes eslint typescript
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update

✓ schema.org compliant