API Surface Discipline
Aug 01, 2023134 min read

API Surface Discipline: Deep Dive #69

AV
Ariel Voss

Principal React Architect

This post follows the plan’s “API Surface Discipline” focus and global requirements:

API surface discipline is the practice of keeping your “public” APIs small, stable, and predictable — especially when routing and rendering are evolving.

In front-end apps, the most important API surfaces are:

  • component props,
  • hooks (internal library APIs),
  • route-level helpers (loading, error, fetch wrappers),
  • and cross-cutting utilities (logging, feature flags).

The discipline is: make it hard to add new surface area and easy to extend behavior without breaking callers.

Worked Example: A Small Fetch API for UI Code

Instead of letting every component call fetch() differently, publish one small API:

  • consistent error shape
  • consistent caching policy
  • consistent logging hooks

Step 1: Define a Stable Result Type

export type ApiError = {
  message: string;
  status?: number;
  code?: string;
};

export type ApiResult<T> =
  | { ok: true; data: T }
  | { ok: false; error: ApiError };

Step 2: Publish One apiFetch() Helper

export async function apiFetch<T>(input: RequestInfo, init?: RequestInit): Promise<ApiResult<T>> {
  try {
    const res = await fetch(input, { ...init, headers: { ...(init?.headers ?? {}) } });
    if (!res.ok) {
      return { ok: false, error: { message: `Request failed`, status: res.status } };
    }
    const json = (await res.json()) as T;
    return { ok: true, data: json };
  } catch (e) {
    return { ok: false, error: { message: String(e) } };
  }
}

Step 3: Keep Components on the Stable Surface

type UserRow = { id: string; name: string };

export async function UsersPanel() {
  const result = await apiFetch<UserRow[]>("https://example.invalid/api/users", { cache: "no-store" });
  if (!result.ok) return <div data-state="error">{result.error.message}</div>;
  return (
    <ul>
      {result.data.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

Discipline Checklist

  • Publish a small surface (apiFetch, stable result type).
  • Move variability behind the surface (caching/logging/retries).
  • Keep UI code on the stable surface to make refactors cheap.