9.7 — fetch without a browser
In 6.7 an envelope left a browser tab. Today the same envelope leaves a plain terminal — no page, no HTML, just a script having a data conversation with a server. JSON out, JSON in.
This tiny shift has a job title hiding inside it: API testing. By the end of the lesson you’ll have written your first API check — every tool for it is already on your belt.
// users.js — no HTML, no page, just Node
const res = await fetch("https://api.shop.com/users/7");
console.log(res.status);
const user = await res.json();
console.log(user.name);
console.log(user.pet?.name ?? "no pet");
// $ node users.js
// 200
// Ada
// no petThe star is an old friend: fetch — 6.7’s envelope, round trip and all — is built into Node (since version 18). Line 2 works in a plain script with zero installs. The envelope simply leaves a terminal now instead of a browser tab.
The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”
Sending data works the same way with options: fetch(url, { method: "POST", body: JSON.stringify(data) }) — 4.13’s stringify finally meets its purpose: objects travel as JSON text. GET reads, POST creates, PUT/PATCH update, DELETE removes — the HTTP verbs, worth recognizing on sight.
One honesty note carried over from 6.7: fetch only rejects on network failure. A 404 or 500 is a “successful” fetch with a bad status — which is precisely why API checks assert on res.status explicitly instead of trusting that “it didn’t throw.”
The browser’s CORS wall (6.7’s bouncer) doesn’t apply here — CORS protects users inside browsers, and there’s no browser. Scripts can call any API they’re authorized for; the authorization usually travels as a header carrying a token from… process.env (9.4’s secrets, completing the circle).
Job note: API tests make superb setup for browser tests too — create the user via the API in one second, then browser-test only the login screen itself. Phase 11 uses this trick constantly; it’s often the difference between a 40-second test and a 4-second one.
⌨️ your first API check
A fake server is provided (so the check is deterministic — no real network). Write the async function that performs a genuine API check: status first, then the parsed body, read safely.
requirements:
- Keep the provided
fakeFetchexactly as is — it stands in for the real network. - Write an async function
checkUser(): await the response, print itsstatus, await the parsed body, print itsname. - Also print the pet’s name with an honest fallback of
"no pet"— the response has no pet field, and your check must not crash (8.4’s pair). - Call
checkUser()at the end.
when you press RUN, the console must show exactly:
✏️ Quick check 1
res.status is 404. Whose side of the conversation made the mistake — yours or the server’s?
✏️ Quick check 2
How many awaits does reading a JSON response take, and why? Type the number.
✏️ Quick check 3
The response body has no pet field. What does user.pet?.name ?? "no pet" evaluate to?
🗣️ Now teach it back
Explain to a friend what API testing is, using today’s script: what fetch does without a browser, why status and body take separate awaits, and why ?. and ?? show up in almost every check.
Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.