Intermediate · Asynchronous JavaScript · topic 41 of 61 · 30 min
fetch: talking to servers
Explanation
HTTP in one paragraph
HTTP is the language browsers and servers use. A client sends a request: a method (GET to read, POST to create, PUT/PATCH to update, DELETE to remove), a URL, headers (extra information like Content-Type) and sometimes a body (the data). The server sends back a response: a status code (200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Server Error), headers and a body, very often JSON.
A GET request
async function getTrain(number) {
const response = await fetch(`https://api.example.com/trains/${number}`);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json(); // also a promise: reading the body takes time
}The Response object
| Property / method | Gives |
|---|---|
| response.ok | true for status 200–299 |
| response.status | the number, e.g. 404 |
| response.headers.get('content-type') | a header value |
| await response.json() | the body parsed as JSON |
| await response.text() | the body as text |
The body can be read only once. Calling json() and then text() on the same response throws "body used already".
Sending JSON with POST
async function createOrder(order) {
const response = await fetch('https://api.example.com/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(order),
});
if (!response.ok) throw new Error(`Could not create order: ${response.status}`);
return response.json(); // e.g. { id: 'OD1023', status: 'PLACED' }
}Timeouts and cancelling with AbortController
async function fetchWithTimeout(url, ms) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
const response = await fetch(url, { signal: controller.signal });
return await response.json();
} finally {
clearTimeout(timer);
}
}
// Newer engines also offer the shortcut fetch(url, { signal: AbortSignal.timeout(5000) }).Aborting really stops the request (unlike Promise.race, which only stops waiting). The fetch promise then rejects with an error named AbortError.
A complete pattern
- Show a loading state.
- await fetch inside try.
- If !response.ok, throw an error with the status.
- Parse JSON and check the shape you expect.
- catch: show a friendly message and log the details.
- finally: hide the loading state.
CORS in one line
A web page can only read responses from another domain if that server allows it with CORS headers (Access-Control-Allow-Origin). A CORS error is fixed on the SERVER, not in your fetch call. Node.js scripts are not limited by CORS.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
fetch: talking to servers · 1/7
In this lesson you will talk to servers with fetch.
Prefer a video by a teacher? Find free videos on “javascript fetch api tutorial async await post json” on YouTube ↗
In real life: PNR status with a fake server
Tests and demos should not call real servers. A booking app's PNR helper accepts a fetch function as a parameter, so tests can pass a fake one that returns ready-made responses, including a 404 for an unknown PNR.
const fakeFetch = async (url) => url.endsWith('/4521')
? { ok: true, status: 200, json: async () => ({ pnr: '4521', status: 'CNF' }) }
: { ok: false, status: 404, json: async () => ({ error: 'Not found' }) };
async function getPnr(pnr, fetchFn = fetch) {
const res = await fetchFn(`https://api.example.com/pnr/${pnr}`);
if (!res.ok) throw new Error(`PNR lookup failed (${res.status})`);
return res.json();
}
getPnr('4521', fakeFetch).then(console.log); // { pnr: '4521', status: 'CNF' }
getPnr('9999', fakeFetch).catch((e) => console.log(e.message)); // PNR lookup failed (404)Practice (0/3 done)
Write getJson(url, fetchFn) that awaits fetchFn(url), throws an Error "HTTP <status>" when response.ok is false, and otherwise returns await response.json(). A fake fetch is provided in the tests.
Write postJson(url, data, fetchFn) that sends a POST with header Content-Type: application/json and the body JSON.stringify(data), and returns the parsed response JSON. The fake fetch echoes what it received.
Write fetchWithTimeout(url, ms, fetchFn) that creates an AbortController, aborts it after ms, passes { signal } to fetchFn, and returns the JSON. The fake slow fetch rejects with an AbortError when the signal aborts.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- async and awaitAsynchronous JavaScript · same module
- fetch and APIsFrontend Web Development · Async JavaScript, modules and tools
- Calling the API with fetchFull-Stack Development · Connecting frontend and backend
- HTTP requests, responses and methodsBackend Development · How the web and backends work
- Loading, errors and slow networksFull-Stack Development · Connecting frontend and backend
- How web requests work (and why that matters)Ethical Hacking and Penetration Testing (legal labs) · Web application testing: Burp Suite and the basics
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
A server replies 404 Not Found. What does the fetch promise do?
Answer: Fulfils with a Response whose ok is false
fetch only rejects on network failure.
Which status code means "created"?
Answer: 201
201 Created is the usual answer to a successful POST.
What must the body of a JSON POST be?
Answer: A string made with JSON.stringify
fetch sends text; stringify the object.
How do you really cancel a fetch?
Answer: AbortController with signal
An aborted signal stops the request and rejects with AbortError.
Where is a CORS error fixed?
Answer: On the server, with the right headers
The server must allow the page's origin.
The server answers your fetch with 404 Not Found. What does fetch do?Related
Answer: It fulfils with a response whose ok is false
fetch only rejects when the request fails completely (for example no network). A 404 is a real answer, so you must check response.ok.
From fetch and APIs
The server answers 404 Not Found. What does await fetch(url) do?Related
Answer: It resolves to a Response with status 404 and res.ok false
fetch only rejects when no answer arrives. A 404 is an answer, so you must check res.ok or res.status yourself.
Which part of an HTTP request carries the JSON data you send?Related
Answer: The body
The body comes after the headers and the empty line, and holds the data.
How do you cancel the notes request when the user leaves the page in React?Related
Answer: Create an AbortController, pass its signal to fetch, and call abort() in the useEffect cleanup
The cleanup runs when the component leaves the screen; abort() cancels the fetch, which rejects with an AbortError you can ignore.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Asynchronous JavaScript”. The module exam comes next.
- Module 8 exam: Asynchronous JavaScript · 12 questions · 25 min, without help. 6 topics of this module still to finish first.
- Then the next module, TypeScript basics. 61 topics left in the course before the final exam.