Modular Data Dashboard
Build a dashboard pulling from multiple APIs, with cancellation, cached state, URL-backed controls, and an accessible chart-or-table alternative.
Practices: Async JavaScript in depth, Browser application architecture, Testing and maintainability
Scenario
Build a small dashboard combining data from at least two independent sources (two different public APIs, or one API plus a local JSON file standing in for a second) — a weather-plus-air-quality view, a repo-stats-plus-issues view, whatever combination is available and interesting. The dashboard’s filter/view controls should live in the URL, so a specific view is shareable and survives a reload.
Requirements
Core
- At least two independently fetched data sources render into the same view, each with its own loading/empty/error state (recall Asynchronous Basics and Data Fetching and Asynchronous JavaScript in Depth) — one source failing must not blank out the other’s already-loaded data.
- Changing a filter or view control updates the URL (via the History API) without a full page reload, and loading the dashboard directly from a URL with parameters restores that exact view.
- Switching filters while a previous request for the same data is still in flight cancels the stale
request (
AbortController) or otherwise ignores its result if it arrives late — no race-condition overwrite of newer data with a stale response. - Repeated identical requests within a short window are served from a simple in-memory cache instead of re-fetching.
- Data is presented as an accessible table (or a chart with an equivalent accessible data table alternative) — never a chart with no non-visual way to access the same data.
Stretch
- A “last updated” timestamp per data source, with a manual refresh control.
- Graceful degradation when one source is slow: show the fast source’s data immediately, the slow source’s once it arrives, rather than waiting for both.
- Debounce a text-filter control so it doesn’t re-fetch on every keystroke.
Reflect
- Where did the race-condition risk actually live in your implementation — which specific state update needed the “is this still the most recent request” guard?
- If a third data source were added, what in your current design would need to change versus what would just work?
Suggested milestones
- Render one data source with proper loading/empty/error states, no URL syncing yet.
- Add the second data source, independently loaded and independently error-handled.
- Wire filter controls to the URL (pushState) and restore state from it on load.
- Add cancellation/staleness handling for rapid filter changes.
- Add the accessible table/chart-alternative presentation and a caching layer.
- Write at least one integration test exercising a filter change end to end.
Acceptance checks
- Loading the dashboard with URL parameters already set (a bookmarked/shared link) restores that exact filtered view on first load.
- Rapidly changing a filter several times in quick succession settles on the result matching the last selected filter, never an earlier one arriving late.
- One data source returning an error still leaves the other source’s data visible and usable.
- All data is reachable via a screen reader — a chart alone, with no accessible table alternative, fails this check.