How do you make a request with fetch?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
fetch returns a promise resolving to a Response. Reading the body is a second async step.
const res = await fetch("/api/users");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const users = await res.json();
Check res.ok — this is the part people miss
fetch rejects only on network failure. A 404 or 500 resolves normally with ok === false, so without that check your error path never runs and you try to parse an error page as JSON.
Sending data
const res = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Mai" }),
});
The body must be a string, FormData, Blob or similar — passing a plain object silently sends "[object Object]". With FormData, do not set Content-Type yourself; the browser adds it with the required multipart boundary.
Reading the response
res.json(), res.text(), res.blob(), res.formData(). The body can only be read once, so store the result rather than calling two of these on the same response.
Options worth knowing
await fetch(url, {
credentials: "include", // send cookies cross-origin
signal: AbortSignal.timeout(5000), // cancel after 5s
cache: "no-store",
});
Cookies are sent automatically for same-origin requests but not cross-origin unless you set credentials, and the server must also allow it via CORS.
A reusable wrapper
async function api(url, options) {
const res = await fetch(url, options);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.status === 204 ? null : res.json();
}
The 204 check matters — calling res.json() on an empty body throws a confusing parse error.
