API Explorer
Build a browser app that fetches data from a public or local mock API, handles loading/empty/error states, and lets a user search and filter what comes back.
Practices: Async basics and fetching, Arrays and objects, The browser and the DOM
Scenario
Pick a public API with no authentication required (a countries API, a jokes API, a books API — the
exact choice doesn’t matter), or build a small local JSON file and fetch it as a stand-in. Build a
page that loads a list from it, lets the user search or filter the results client-side, and clearly
communicates what’s happening at every stage of the request — not just the happy path.
Requirements
Core
- On load, the page fetches data and shows a visible loading state until it resolves.
- A successful response with results renders them as a list (cards, table rows — your choice).
- A successful response with zero results shows a distinct, honest empty state — not a blank screen and not the loading state left on forever.
- A failed request (network error, non-OK status) shows a clear error message, not a silent failure or an uncaught rejection in the console.
- A search or filter input narrows the already-fetched results client-side, without re-fetching on every keystroke.
- Rendering never trusts API data blindly: a missing field doesn’t crash the page (defensive rendering — check before you assume a property exists).
Stretch
- Debounce the search input so filtering doesn’t run on every single keystroke.
- Add a second, independent
fetch(a related endpoint, or a details view fetched on click) and handle its loading/error states separately from the first. - Use
Promise.allto fetch two endpoints concurrently and combine their results.
Reflect
- Where in your code is “we have zero results” distinguished from “we’re still loading” from “the request failed”? Are those three states represented explicitly, or inferred from other variables in a way that could go wrong?
- What would break if the API’s response shape changed slightly (a renamed field, a nested object instead of a flat one)? How much of your rendering code would need to change?
Suggested milestones
- Fetch and
console.logthe raw response — confirm the request and data shape before rendering anything. - Render the list for the successful case only.
- Add the loading state, shown before the fetch resolves.
- Add the empty and error states.
- Add client-side search/filtering over the already-fetched data.
Acceptance checks
- Throttling the network to “slow 3G” in DevTools shows the loading state for a visible period before results appear.
- A search term matching nothing shows the empty state, not a blank area.
- Turning off network access (or pointing the fetch at a bad URL) shows the error state, not a console-only failure.
- Typing in the search box narrows the visible list without triggering a new network request each time (check the Network tab).