The Crisis: "Wait, the API field name changed?"
In a distributed system, the "Interface" between the frontend and backend is the most fragile point of failure.
We’ve all been there: The backend developer renames user_id to id in the database to follow a new convention. They update the API response but forget to tell the frontend team. The code deploys, and suddenly the mobile app or web dashboard crashes for thousands of users because it's trying to read a property that no longer exists.
This is called Type Drift, and in a fast-moving team, it is the #1 cause of "silent" production bugs.
The Solution: The "Shared Contract"
In modern System Design, we treat the API not as a set of loose JSON objects, but as a Strict Contract that neither side can break without a loud, immediate compile-time error.
Instead of writing types for your Frontend and types for your Backend separately (and hoping they match), you define them once in a shared space.
3 Ways to Enforce the Contract:
1. The Monorepo + Shared Types
If your frontend and backend live in the same repository (Monorepo), this is the simplest win. You create a packages/shared-types folder.
- The Workflow: Define your Zod schemas or TypeScript interfaces there.
- The Result: If a backend dev changes a field in the shared package, the Frontend build will immediately throw a red squiggly line in VS Code.
2. tRPC: Moving Beyond Fetch
If you are using TypeScript on both sides of the stack, tRPC is a game-changer. It eliminates the need for fetch() or axios boilerplate.
- The Workflow: You export your Backend’s router type. The Frontend imports that type.
- The Result: You get full autocompletion of your API endpoints and their response shapes. It feels like calling a local function even though it’s a network request.
3. OpenAPI & Code Generation (The Polyglot Way)
If your backend is in Go or Python and your frontend is in React, you can't share a .ts file. In this case, you use OpenAPI (Swagger).
-
The Workflow: The Backend generates a
swagger.jsonfile. -
The Result: Tools like
openapi-typescriptscan that file and automatically generate a perfect TypeScript definition for the Frontend to consume.
Why this is a "System Design" Win:
1. Safety (Build-Time vs. Runtime)
Without type safety, you find bugs when a user clicks a button and the app goes white. With type-safe APIs, you find bugs at Build Time. If the contract is broken, the CI/CD pipeline fails, and the code never reaches the user.
2. Developer Velocity
Frontend developers no longer have to waste time in Postman or Burp Suite trying to "guess" what the API returns. They just type data. and let the IDE Autocomplete show them the available fields.
3. Confident Refactoring
You can confidently refactor your backend architecture. If you rename a field or change a data type from a string to a Date object, you’ll immediately see exactly which parts of your frontend need to be updated.
Takeaway
A system is only as strong as its connections. By moving from "loose JSON" to "strict contracts," you turn your API from a liability into a shield. Type safety doesn't just prevent bugs; it builds trust between teams.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.