Level 4 · Full-Stack Application Development · Course 4.2 Frontend Architecture

Module 38: API Integration

Goal: connect your React app to an API: fetch data with proper loading and error states, send changes, and use caching so data stays fast and fresh. You'll use a practice API now and your own backend from Module 41.

You'll need: your enquiries app from Module 37 and Module 25's API skills.

Lessons

  1. 1An API client and a practice server15–25 minutes✓
  2. 2Fetching with loading and error states15–25 minutes✓
  3. 3Sending changes15–25 minutes✓
  4. 4Caching and stale data15–25 minutes✓
  5. 5Handling real-world API problems15–25 minutes✓

🛠️Module practice: the enquiry app on an API

  1. An api.ts client with typed functions and an ApiError class.
  2. Every screen with loading, error (with retry) and empty states.
  3. Create, update and delete with mutations, disabled buttons while sending, and cache invalidation.
  4. Sensible staleTime, background refresh indicator, offline message.
  5. Works against json-server; reports failures clearly when the server is down. Commit.

✅Module check

Explain in a few sentences, in your own words:

What does a good React app do when it talks to an API?

Show a good answer

A good answer mentions: API calls live in one client module that checks responses and throws meaningful errors; screens handle loading, error (with retry) and empty states; changes are sent as mutations with buttons disabled while sending, clear success and failure messages, and refetching or invalidating the cache afterwards. Caching with sensible freshness makes it fast; status codes like 401, 403, 404 and 422 are handled appropriately; data shapes are checked at the boundary, and no secrets are put in frontend code.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. Why keep every API call in one api.ts file?

Why each option is right or wrong

  • “Browsers allow fetch from only one file per site” (Incorrect): Any file can call fetch; it's a design choice to centralise it.
  • “It makes every request travel to the server faster” (Incorrect): Network speed is the same; the benefit is maintainability.
  • “It hides the API addresses from people using the site” (Incorrect): Frontend code can still be read; centralising doesn't hide anything.
  • “Addresses, headers and errors are handled in one place” is correct.

    If fetch calls are scattered across components, changing the server address or adding a sign-in header means editing many files. One API module gives every call the same base URL, headers and error handling, and components just call getEnquiries().

    • Easier testing: the module can be replaced with a pretend API.
    • Easier change: a new server address is one edit.

📖 Revise: Lesson 1: An API client and a practice server

Question ID module-38-q1 · Report a mistake in this question
2. Can you put a payment secret key in VITE_PAYMENT_KEY?

Why each option is right or wrong

  • “Yes, .env files are private, so anything in them is safe” (Incorrect): The .env file isn't uploaded, but VITE_ values are copied into the public code.
  • “Yes, as long as the site uses HTTPS” (Incorrect): HTTPS protects data in transit; the key is still in the code visitors download.
  • “Yes, if the variable name is long and hard to guess” (Incorrect): Names don't protect values; the key is visible in the code.
  • “No, VITE_ variables are built into the frontend anyone can read” is correct.

    Vite copies VITE_ variables into the JavaScript sent to every visitor. Anyone can open developer tools and find them. Secret keys belong on the server, which makes the payment call on the frontend's behalf.

    • Safe in VITE_: public values, like a publishable key or API address.
    • Server only: secret keys, database passwords.

📖 Revise: Lesson 1: An API client and a practice server

Question ID module-38-q2 · Report a mistake in this question
3. What three states should every data-fetching screen handle?

Why each option is right or wrong

  • “Starting, sending and finishing, one for each stage of the request” (Incorrect): These aren't states the person sees; what matters is loading, error and success.
  • “Online, offline and sleeping, matching the device's network status” (Incorrect): Network status matters, but the screen still needs loading, error and success.
  • “Fast, medium and slow responses” (Incorrect): Speed varies, but the screen states are loading, error and success.
  • “Loading, error with retry, and success including empty” is correct.

    Requests take time, can fail, and can return nothing. A screen that handles only success shows a blank or broken view the rest of the time. Plan all three, with an empty message inside success.

    • Loading: a spinner or skeleton.
    • Error: a plain message and a Retry button.

📖 Revise: Lesson 2: Fetching with loading and error states

Question ID module-38-q3 · Report a mistake in this question
4. Two components on the same page appear at the same moment, and both call useQuery({ queryKey: ["enquiries"] }) while nothing is cached yet. How many requests are made?

Why each option is right or wrong

  • “Two, one for each component” (Incorrect): While the first request for that key is still in flight, the second component joins it instead of starting its own.
  • “None, until the page is reloaded” (Incorrect): The query runs when the components first appear.
  • “Two every second, until one is removed” (Incorrect): There's no repeated polling unless you turn it on.
  • “One; they share the cached data” is correct.

    TanStack Query uses the key to identify data. When two components ask for the same key at the same time, it sends one request and gives both the result, then keeps it in the cache.

    • Same key = same data.
    • Not a fixed count: later on, refetch rules (stale time, returning to the tab, reconnecting) can send more requests for the same key.
    • Different filters: include them in the key to get separate entries.

📖 Revise: Lesson 4: Caching and stale data

Question ID module-38-q4 · Report a mistake in this question
5. Why disable a "Save" button while the request is in progress?

Why each option is right or wrong

  • “The request fails with an error if the button stays enabled” (Incorrect): The request succeeds; extra clicks send duplicates.
  • “It makes the request reach the server and finish sooner” (Incorrect): Disabling doesn't speed the request up.
  • “Browsers require it for all forms” (Incorrect): Browsers don't require it; it's good design.
  • “To stop double-clicks sending the same data twice” is correct.

    People often click again when nothing seems to happen. Each click sends another request, which can create duplicate enquiries or payments. Disabling the button, and showing "Saving…", prevents it.

    • With TanStack Query: use mutation.isPending.
    • Server side too: checks against duplicates help.

📖 Revise: Lesson 3: Sending changes

Question ID module-38-q5 · Report a mistake in this question
6. What does stale-while-revalidate mean?

Why each option is right or wrong

  • “Delete cached data as soon as it's older than a minute” (Incorrect): The cache is shown first, then refreshed; it isn't simply deleted.
  • “Show nothing until the server confirms the data is fresh” (Incorrect): That's the opposite: cached data is shown straight away.
  • “Never fetch again once data has been cached” (Incorrect): It fetches again in the background to stay current.
  • “Show cached data immediately while fetching a fresh copy in the background” is correct.

    When you return to a screen, the cached list appears straight away instead of a spinner. Meanwhile a fresh copy is fetched, and the screen updates quietly if anything changed.

    • Feels fast: no waiting on screens you've already seen.
    • Stays correct: the fresh copy replaces old data.

📖 Revise: Lesson 4: Caching and stale data

Question ID module-38-q6 · Report a mistake in this question
7. Should exchange rates and a list of Indian states have the same staleTime?

Why each option is right or wrong

  • “Yes, all queries should use the default setting” (Incorrect): Defaults are a starting point; data that changes at different speeds needs different settings.
  • “Yes, so the app stays consistent” (Incorrect): Consistency of settings doesn't help when the data changes at very different rates.
  • “No, the larger list needs a shorter staleTime” (Incorrect): Size doesn't matter; how often the data changes does.
  • “No, set each by how fast it changes” is correct.

    Exchange rates change by the minute, so they go stale fast. The list of states rarely changes, so it can stay fresh for hours or days, saving needless requests.

    • Short staleTime: live prices, notifications.
    • Long staleTime: reference lists, settings.

📖 Revise: Lesson 4: Caching and stale data

Question ID module-38-q7 · Report a mistake in this question
8. The server returns 422 "email already registered". Where should the message appear?

Why each option is right or wrong

  • “In the browser console, where developers can read the full details” (Incorrect): People using the form don't see the console.
  • “As a generic "Something went wrong" popup” (Incorrect): That hides the useful detail the server sent.
  • “Nowhere; the form should quietly try again” (Incorrect): Retrying won't help; the email is already registered.
  • “Next to the email field, like any validation error” is correct.

    This is a problem with the email the person entered. Showing it beside that field, the same way as browser-side errors, tells them exactly what to change.

    • Map server errors: to fields where possible.
    • General errors: show at the top of the form.

📖 Revise: Lesson 5: Handling real-world API problems

Question ID module-38-q8 · Report a mistake in this question
9. What does invalidating the ["enquiries"] query do after a change?

Why each option is right or wrong

  • “Deletes the changed enquiries from the server's database” (Incorrect): It only affects the cache in the browser.
  • “Shows a warning to the person that their list is out of date” (Incorrect): It quietly refetches; there's no warning to the person.
  • “Stops the list loading until the page reloads” (Incorrect): It triggers a fresh load straight away.
  • “Marks the cached list as outdated so it's fetched again” is correct.

    After you add or edit an enquiry, the cached list no longer matches the server. Invalidating its key tells TanStack Query to refetch, so every screen showing the list updates.

    • Typical place: a mutation's onSuccess.
    • Alternative: update the cache directly with the server's response.

📖 Revise: Lesson 4: Caching and stale data

Question ID module-38-q9 · Report a mistake in this question
10. Why check the shape of API data with a schema at the boundary?

Why each option is right or wrong

  • “TypeScript types already check API data while the app runs” (Incorrect): Types are removed before running, so they can't check live data.
  • “Schemas make the response download more quickly” (Incorrect): Schemas check data; they don't speed downloads.
  • “The server rejects requests that don't use a schema” (Incorrect): The schema runs in your app; the server doesn't know about it.
  • “API changes are reported clearly in one place” is correct.

    If the server renames a field, unchecked data flows into components and fails somewhere confusing. A schema check, for example with Zod, as data arrives reports "expected status to be a string" right where the mismatch enters.

    • Bonus: the schema can produce the TypeScript type.
    • Validate at the edges: inside, the code can trust the data.

📖 Revise: Lesson 5: Handling real-world API problems

Question ID module-38-q10 · Report a mistake in this question

ProLearners Assist