28. JavaScript Fetch API
What you will learn
- How to request data with
fetch() - How to check the response and read JSON
- How to send data with POST
- How to handle errors, and what CORS is
The Try it Yourself editor blocks network requests, so the real fetch() examples are for reading and copying. A pretend fetch example further down lets you practise the same pattern here. The web addresses in this lesson are placeholders, not real services.
What is fetch?
fetch() asks a server for data without reloading the page. It returns a promise that resolves to a response. This is how pages load fresh data, submit forms in the background, and talk to APIs.
A basic request
Syntax
async function loadLesson() {
const response = await fetch("https://example.com/api/lesson/1");
const data = await response.json();
console.log(data.title);
}
loadLesson();
Two awaits, because two things take time: first the response arrives, then its body is read and turned into an object.
Always check response.ok
Important: fetch() only rejects when the network itself fails. A “404 Not Found” or “500 Server Error” still counts as a successful fetch. You must check it yourself.
Syntax
async function loadLesson(id) {
try {
const response = await fetch(`https://example.com/api/lesson/${id}`);
if (!response.ok) {
throw new Error("Server answered " + response.status);
}
const data = await response.json();
document.getElementById("title").textContent = data.title;
} catch (error) {
document.getElementById("title").textContent = "Sorry, the lesson could not be loaded.";
console.error(error);
}
}
| Property | Meaning |
|---|---|
response.ok |
True for status 200 to 299 |
response.status |
The number, such as 200 or 404 |
response.json() |
Reads the body as JSON |
response.text() |
Reads the body as plain text |
Sending data with POST
Pass a second argument describing the request. To send JSON, set the method, a header, and a stringified body.
Syntax
async function sendMessage(name, message) {
const response = await fetch("https://example.com/api/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: name, message: message })
});
if (!response.ok) {
throw new Error("Could not send: " + response.status);
}
return response.json();
}
Practise with a pretend fetch
This example fakes a server with a promise, so the same await, ok, and json() steps run right here. Press Try it Yourself, then change the address to /api/missing to see the error path.
Example
<p id="demo">Loading...</p>
<script>
// A pretend server: no real network is used
function fakeFetch(url) {
return new Promise(function (resolve) {
setTimeout(function () {
if (url === "/api/lesson") {
resolve({
ok: true,
status: 200,
json: function () { return Promise.resolve({ title: "JavaScript Fetch API", order: 28 }); }
});
} else {
resolve({
ok: false,
status: 404,
json: function () { return Promise.resolve({}); }
});
}
}, 700);
});
}
async function loadLesson(url) {
const out = document.getElementById("demo");
try {
const response = await fakeFetch(url);
if (!response.ok) {
throw new Error("Server answered " + response.status);
}
const data = await response.json();
out.textContent = "Loaded: " + data.title + " (lesson " + data.order + ")";
} catch (error) {
out.textContent = "Sorry, that could not be loaded. " + error.message;
}
}
loadLesson("/api/lesson");
</script>
What you see (after about 0.7 seconds)
Loaded: JavaScript Fetch API (lesson 28)
Showing loaded data safely
Data from a server can contain anything. Put text on the page with textContent or createElement, never innerHTML, unless you fully trust and control the source.
Loading states
Network requests take time and sometimes fail. Good pages show a “Loading…” message first, clear it when done, and show a helpful message on failure. The finally block is a good place to remove the loading message.
CORS: why some requests fail
For safety, a browser only lets your page read a response from another website if that site allows it. The rule is called CORS (Cross-Origin Resource Sharing). If you see a CORS error in the console, the server you are calling has not given permission to your site. You cannot fix that from your JavaScript. The server owner must allow it, or you call the service from your own server.
Keep secrets out of the browser
Anything in your JavaScript can be read by every visitor. Never put passwords, secret API keys, or tokens in front-end code. If a service needs a secret key, call it from a server you control, and let the browser talk to your server.
Other useful options
AbortControllercancels a request, for example after a timeout.- Add query strings with
new URLSearchParams({ q: "html" }), which also encodes special characters. - Check the Network tab in the browser’s developer tools (F12) to see every request, its status, and its response.
Common mistakes
- Not checking
response.ok. - Forgetting
awaitbeforeresponse.json(). - Forgetting
JSON.stringifyand theContent-Typeheader on POST. - Putting server data into
innerHTML. - Storing secret keys in front-end code.
- Not handling failures, so visitors see a blank page.
Exercise
Write an async function showUser(url) that awaits fakeFetch(url). If response.ok is false it should show Not found (404), using the status. On success it should show User: Sam. Try both addresses.
Show solution
async function showUser(url) {
const out = document.getElementById("demo");
try {
const response = await fakeFetch(url);
if (!response.ok) {
throw new Error("Not found (" + response.status + ")");
}
const data = await response.json();
out.textContent = "User: " + data.name;
} catch (error) {
out.textContent = error.message;
}
}
showUser("/api/user");
Add this inside the script, below fakeFetch.
Knowledge check
1. Does fetch() reject the promise on a 404 response?
No. It rejects only on network failure, so check response.ok.
2. Which method reads a JSON response body?
response.json()
3. Why must secret API keys not be in front-end code?
Every visitor can read your JavaScript.
Summary
fetch()returns a promise of a response. Checkresponse.ok, then read it withjson().- Send data with
method,headers, and a stringifiedbody. - Handle errors and CORS limits, show data safely, and never expose secrets.