1. Introduction
The Fetch API is the modern, Promise-based interface for making HTTP requests in JavaScript, replacing the older XMLHttpRequest. It is built into browsers and, since Node.js 18, is also available globally in Node without any extra library. Calling fetch(url) returns a Promise that resolves to a Response object once the HTTP response headers have been received, and you then read the body (as JSON, text, etc.) using further Promise-returning methods like response.json().
Cricket analogy: Calling fetch(url) is like sending a runner to fetch the scoreboard update -- you get confirmation (the Response) once the runner reaches the board, but you still need a second trip, like response.json(), to actually read the detailed over-by-over figures.
2. Syntax
// Basic GET request
const response = await fetch("https://api.example.com/users/1");
const data = await response.json();
// POST request with a JSON body
const response2 = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Alice" }),
});
// Checking for HTTP errors -- fetch does NOT do this for you
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}3. Explanation
fetch() returns a Promise, so it naturally fits async/await and .then() chaining. However, the single most important gotcha is this: fetch's returned Promise only rejects on a NETWORK failure (DNS failure, connection refused, CORS block, offline, etc.) -- it does NOT reject just because the server responded with an error status like 404 Not Found or 500 Internal Server Error. Those still count as a 'successful' fetch, because a valid HTTP response was received. To detect an HTTP-level failure, you must explicitly check response.ok (true for status codes 200-299) or inspect response.status yourself, and throw/handle the error manually.
Cricket analogy: fetch() only 'appeals unsuccessful' (rejects) if the ball never reaches the umpire at all, like a broken stump-mic (network failure) -- a wrong decision like a wrongly given out (404/500) still counts as a completed review that you must manually check via response.ok.
Forgetting to check response.ok is one of the most common real-world bugs with fetch. Code that does const data = await response.json(); if (data.error) ... will often still 'succeed' at parsing an error payload as if it were valid data, silently masking a 404 or 500. Always check response.ok (or response.status) before trusting the parsed body.
4. Example
This example mocks fetch with a Promise-based function (so it runs anywhere, without a real network) to demonstrate that a 404 response still resolves successfully -- it must be checked manually.
Cricket analogy: Just as a scoreboard operator can simulate a 'no result' match outcome on a practice board without a real stadium, this example mocks fetch to show a 404 still resolves normally -- you must check it yourself, like double-checking the scoreboard reading.
async function mockFetch(url) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
ok: false,
status: 404,
json: async () => ({ error: "Not Found" }),
});
}, 50);
});
}
async function loadData(url) {
try {
const response = await mockFetch(url);
console.log("Fetch completed, status:", response.status);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
console.log("Data:", data);
} catch (err) {
console.log("Caught error:", err.message);
}
}
console.log("Start");
loadData("/api/user/999");
console.log("End");5. Output
Start
End
Fetch completed, status: 404
Caught error: HTTP error: 4046. Key Takeaways
- fetch() returns a Promise that resolves to a Response once headers arrive; it works naturally with async/await.
- fetch's Promise rejects ONLY on network-level failures, never merely because of an HTTP error status code.
- Always check response.ok (or response.status) before treating the response as successful.
- Reading the body (response.json(), response.text()) is itself an additional asynchronous step returning its own Promise.
- Since Node.js 18, fetch is available globally without any extra package.
Practice what you learned
1. When does the Promise returned by fetch() reject?
2. How do you correctly detect that a fetch response represents an HTTP error like 404?
3. What does response.json() return?
4. In the module example, mockFetch resolves with `{ ok: false, status: 404, ... }`. What happens if the calling code never checks response.ok?
5. Since which Node.js major version has fetch been available as a built-in global, without any extra package?
Was this page helpful?
You May Also Like
Promises in JavaScript
Understand the Promise object, its three states, and how .then/.catch/.finally chaining replaces nested callbacks.
async/await in JavaScript
Learn how async/await provides synchronous-looking syntax for working with Promises, including error handling with try/catch.
Working with JSON in JavaScript
Learn how to convert JavaScript values to and from JSON text using JSON.stringify and JSON.parse, and understand their limitations.
Error Handling in JavaScript
How JavaScript represents runtime failures with Error objects and the built-in TypeError, RangeError, ReferenceError, and SyntaxError types.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics