Lesson 1 of 30
How a frontend actually consumes an API — and how 'binding' data to the UI is just state driving a render, the same idea from the useState lesson.
14 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
A search-as-you-type input fires a fetch on every keystroke. An older response sometimes overwrites a newer one already on screen. What actually causes this?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A strong answer covers
Likely follow-ups
A REST API is a set of URL endpoints a server exposes, organized around resources (/users, /users/42/posts) and standard HTTP verbs that say what to do with them: GET (read), POST (create), PUT/PATCH (update), DELETE (remove). REST is an architectural style, not a specific format — JSON is just the common choice for the data those endpoints send back.
"Binding" data to the UI isn't a separate mechanism you learn — it's the same idea as the useState lesson: fetched data becomes state, and state drives what renders. Nothing new, just a value that happened to come from a network call instead of a click.
function UserList() {
const [users, setUsers] = useState([]);
const [status, setStatus] = useState("loading"); // loading | ready | error
useEffect(() => {
fetch("/api/users")
.then((res) => {
if (!res.ok) throw new Error(`Server said ${res.status}`);
return res.json();
})
.then((data) => {
setUsers(data);
setStatus("ready");
})
.catch(() => setStatus("error"));
}, []);
if (status === "loading") return <p>Loading…</p>;
if (status === "error") return <p>Couldn't load users.</p>;
return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
fetch() resolves with a Response, not the data — you still have to call .json() (itself another promise) to get the parsed body. Once that data lands in setUsers, it's ordinary state; the "binding" is just the component re-rendering with it, same as any other state change.
GET /users/42 — a URL identifies a resource (user 42), not an action.
201 (created) vs 200 (ok) vs 204 (no content) vs 304 (not modified) vs 429 (rate limited) — each implies a different thing your code should do, not just "success or not."AbortController (cancel the previous request) or a request-id guard (ignore a response that isn't the latest one you sent)."Fetch this list and show it" is a standard screening-round task, and what separates a strong answer isn't the happy path — it's whether you handle loading and error states, check the status code meaningfully, and know how to prevent stale responses from overwriting fresh ones.