What you'll be able to do
By the end of this page you should be able to fetch a URL, read JSON with response.json(), use async/await, and know that HTTP error statuses (404, 500) do not reject the promise by themselves — you must check response.ok (next post goes deeper).
Previous post: async/await everyday.
Who this is for
- People loading a public JSON API or a
/api/...route from the browser - Beginners who only used static HTML until now
- Anyone who saw
fetchfail only on network errors and wondered why 404 looked “successful”
You can skip this if fetch + JSON is routine. Come back when status handling bites you.
Minimal GET
const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await res.json();
console.log(data);
Scenario A — public demo API. Fine for learning in the browser.
Scenario B — your own backend. Same shape: URL → response → parse body.
fetch returns a Promise for a Response object. The body is not parsed until you call .json(), .text(), etc. (also promises).
response.ok is not automatic throw
const res = await fetch("/api/missing");
console.log(res.status); // e.g. 404
console.log(res.ok); // false
// Promise still fulfilled — no throw yet
Scenario A — network down / CORS block. That rejects the promise — try/catch sees it.
Scenario B — server says 404. Promise fulfills with a Response; you must check ok or status. Full patterns in the next post.
Headers and method (light)
await fetch("/api/items", {
method: "GET",
headers: { Accept: "application/json" },
});
Scenario A — GET list. Default method is GET.
Scenario B — POST later. You will pass method: "POST" and often body: JSON.stringify(...) with Content-Type — keep that for when you build forms against a real API.
CORS in one sentence
Browsers block reading many cross-origin responses unless the server allows it. If the Network tab shows the request but your JS gets a TypeError, it may be CORS — not “fetch is broken.”
Scenario A — same origin (learn.aivoicepro.in calling its own /api). Usually fine.
Scenario B — random third-party API. Needs proper CORS headers or a backend proxy.
A tiny practice file
Save as fetch-basics.html and open via a local server if needed.
<!DOCTYPE html>
<html>
<body>
<button id="go">Load todo</button>
<pre id="out"></pre>
<script>
document.getElementById("go").addEventListener("click", async function () {
const out = document.getElementById("out");
out.textContent = "loading…";
try {
const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await res.json();
out.textContent = JSON.stringify(data, null, 2);
} catch (err) {
out.textContent = "Network/CORS error: " + err.message;
}
});
</script>
</body>
</html>
Mistakes I see a lot
1. Assuming 404 throws. Check res.ok (next post).
2. Forgetting await res.json().
3. Double-parsing. Do not JSON.parse on an object you already got from .json().
4. Ignoring CORS. Read the console + Network tab.
5. Fetching on every keystroke without cancel. AbortController is Blog #59.
What to try before the next post
- Load a public JSON URL and print fields.
- Hit a bad URL path; log
statusandok. - Wrap
fetchintry/catchand unplug network to see rejection. - Build
fetch-basics.html.
Next in this series: HTTP status and error handling — ok, status checks, and linking to try/catch habits from Blog #22.
Try this next outside the series
Async code gets much easier when you see the same ideas on the browser side and the server side.
- Node.js async patterns — see promises and async functions in real backend flows
- Node.js streams intro — continue from simple async waits into data that arrives over time