CodingNic

Client State and Rendering

Give API Requests One Shared Path

Client State and Rendering 18 min read

Give API Requests One Shared Path

Open client/src/lib/api.js.

This file is the client’s HTTP boundary. Components should ask it for data instead of each component creating its own fetch() options and error handling.

The starter already has a request() helper. Strengthen it so a network failure becomes a useful application error instead of an unhandled browser exception.

Replace the current helper with:

javascript
const BASE = "/api";

async function request(path, options = {}) {
  let response;

  try {
    response = await fetch(`${BASE}${path}`, {
      headers: { "Content-Type": "application/json" },
      ...options,
    });
  } catch {
    throw new Error("Couldn't reach the server. Check that the API is running and try again.");
  }

  if (!response.ok) {
    const body = await response.json().catch(() => ({}));
    throw new Error(body.error || `Request failed (${response.status})`);
  }

  if (response.status === 204) return null;
  return response.json();
}

What each part does

BASE is the common /api prefix. Keeping it in one constant means exported functions only need to name their resource path.

The try/catch surrounds fetch(). A network failure—such as a stopped server—does not produce an HTTP response at all, so it must be handled separately from response.ok.

response.ok handles HTTP failures such as 400, 404, or 500. The code first tries to read the server’s { error } message so the client can show the useful message the API provided.

A 204 response has no JSON body, so the helper returns null instead of trying to parse an empty response.

All successful JSON responses are returned with response.json().

The existing exported functions can stay small:

javascript
export const getTransactions = () => request("/transactions");
export const getCategories = () => request("/categories");

Test it

With both servers running, reload the Ledger and open the browser Network panel. Confirm the client requests /api/transactions and /api/categories.

Now stop the API server and reload the page. The request helper should throw the readable server-connection error instead of exposing a raw TypeError: Failed to fetch message.

Restart the server before continuing.

Checkpoint

All client API functions use one request helper, HTTP errors become useful Error messages, and a server that cannot be reached produces a controlled failure.