API Modelling
Put a layer between external APIs and your UI that parses raw responses into your own domain models, so a backend change touches one adapter instead of forty components.
When a UI consumes an API directly, every component ends up knowing the backend’s field names, quirks and nesting. Then the
backend renames cust_name to customerName, and you’re editing forty files. API modelling is the fix: define what you
expect the API to deliver, as your own model, and translate at one boundary.
The idea
- Define the shape you need. Fields and types are explicit, so consumers don’t have to guess what the API returns.
- Adapt at the edge. One function per resource turns the raw payload into your domain model. If the API changes, only the adapter changes.
- Get tooling for free. Typed models give autocomplete and compile-time checks everywhere they’re used.
This is the adapter pattern, sometimes called an anti-corruption layer, plus the dependency inversion from SOLID React: components depend on your model, not on someone else’s API.
Validate, don’t just type
TypeScript types vanish at runtime, so a type alone won’t save you from a payload that changed shape. A schema library parses and types in one step, and fails loudly at the boundary instead of quietly deep in a component:
import { z } from "zod";
const ApiCustomer = z.object({
cust_name: z.string(),
email_addr: z.string().email(),
addr: z.object({ street: z.string(), city: z.string(), zip: z.string() }),
});
export type Customer = { name: string; email: string; address: { street: string; city: string; zip: string } };
export const toCustomer = (raw: unknown): Customer => {
const c = ApiCustomer.parse(raw); // throws on contract drift
return { name: c.cust_name, email: c.email_addr, address: c.addr };
};
Related moves
- Generate types from contracts when a spec exists (OpenAPI, GraphQL codegen), and keep a hand-written domain model for UI concerns on top.
- Separate server state from client state. Data fetched from services is a cache; let a data library manage staleness and refetching, and keep only real UI state in stores.
- A backend-for-frontend can do this modelling once, server-side, when one screen fans out to many services.
Testing gets easier
With a model layer, components test against plain domain objects, and fixture builders make test data readable. Mock at the network so the adapter runs too (MSW (Mock Service Worker)).
In practice
On an enterprise React app backed by many microservices, an explicit model layer meant that backend changes landed as small, contained adapter edits. Later, when we put an API gateway in front of everything, the switch was a small change for the same reason: the UI only knew about one layer. That story is in Rolling Out an API Gateway. Feature-based structure keeps these adapters next to the features that use them (Bulletproof React).
- #api-design
- #typescript
- #zod
- #architecture
- #anti-corruption-layer
↩ Linked from (7)
Internal Developer Platform · Where Platforms Fit: DDD Subdomains · API Modelling · Bulletproof React · Zustand Transient Updates · AJAX Polling
- Bulletproof ReactGrowing
…roposal for the team was concrete, with a working example instead of a slide. Related habits: SOLID React and API Modelling.
…lly one wrong type at a boundary, such as an API response or a shared helper. Typing the data layer properly (API Modelling) cleared whole swathes at once. Refused to cheat. No blanket any, no @ts-ignore carpet. Where a…
- Preventing XSS in ReactEvergreen
Validate data at the boundary — everything from servers and third-party APIs (API Modelling). Render through JSX and avoid the escape hatches. Sanitise when you can't avoid HTML. Content-Security-Policy. A strict CSP (sc…
- Rolling Out an API GatewayGrowing
…ront end that only knew about one host. Because the UI's API calls already went through a single model layer (API Modelling), switching to the gateway was a small change on the front-end side.
- SOLID ReactGrowing
…s, and tests can pass in a fake. This is the same idea as an anti-corruption layer at the data boundary — see API Modelling.
- Types of FailureGrowing
…isbehaving proxy (a small Byzantine taste). Timeouts, retries with limits, schema validation at the boundary (API Modelling) and clear loading and error states are the same ideas at a smaller scale. Designing what happen…
↪ Links to (4)
Related by topic
- Growingcase study
A Testing Strategy Teams Actually Adopted
Frontend craft - Growingcase study
Building a Graph Component Library
Frontend craft - Growingcase study
Chairing a Cross-Team UI Guild
Career - Seed
Convex
Frontend craft