Skip to main content
Handbook/Architect/Page 29 · API Design

Contracts That Last

Share

Share this page

Pass it to someone who needs it.

Star on GitHub

Key takeaway: Design the contract first

Your frontend asks your backend for data, and the backend answers. The exact shape of that exchange, what you send and what comes back, is a promise both sides rely on. Change it carelessly and every screen that read the old shape breaks at once. This chapter gets you a contract that stays stable as the app grows.

3.5.1Design the contract first

Your API is the set of addresses your app exposes for others to call. Each one is an endpoint: a single URL plus a method (GET /posts, POST /posts) that does one job. The contract is the agreed shape of every request and response those endpoints exchange.

Decide that shape before the agent writes a single handler. Designing the contract before you build anything is called API-first design. When the request and response are pinned down first, the frontend and backend can be built in parallel against the same agreement instead of guessing at each other.

3.5.2Your frontend and backend can share one project

Two programs does not mean two projects. In this book's stack, the single project you scaffolded serves both halves: your pages are the frontend, and the files under its API route folder are the backend. The contract still matters inside one project, because only the backend can be trusted with anything private.

Split them into two packages in one repo, a monorepo, or into two separate repos. Do that only when the halves deploy separately, or when a second client, a mobile app say, calls the same API. Before that the split buys you nothing and costs you a second build to keep working.

3.5.3Consistent shapes and errors

Wrap every response in one consistent envelope, the same outer shape whether the call succeeds or fails. It carries a success flag, the data, the error, and a meta block for pagination, serving a long list one page at a time. Here it is in JSON, the plain text format APIs use to send data:

{ "success": true, "data": { "id": 42, "title": "First post" }, "error": null, "meta": { "page": 1, "perPage": 20, "total": 137 } }

A failure reuses the same envelope, flips the flag, and fills error instead of data:

{ "success": false, "data": null, "error": { "code": "not_found", "message": "No post with id 42" } }

Give each error a stable code your frontend can branch on, a human message, and a real HTTP status code. That is the three-digit number the web uses to report how a request went (MDN lists them): 200 for success, 404 for not found, 422 for bad input.

3.5.4Versioning without breaking clients

Put a version in the path from day one (/v1/posts). Adding a new optional field is safe: old clients ignore it, so it stays in v1. Removing or renaming a field breaks anyone reading the old shape, so that goes in a new /v2 while v1 keeps running.

This is exactly the split semantic versioning formalizes: additive is a minor change, breaking is a major one. You do not cut clients off, you give them a version to move to on their own schedule.

Additive changes stay in v1; breaking changes get a new version.

This prompt hands the whole contract to your agent:

Ready prompt
Act as a senior engineer designing my API contract. First read my spec and my data model. Endpoints must serve the stories in that spec and reuse the entity and field names from that model, never new ones. Define one consistent response envelope for every endpoint: a success flag, a data field, an error object, and a meta block for pagination. Give me the exact JSON for a success and an error response, a small set of stable error codes, and the HTTP status each maps to. Then propose a versioning scheme (path or header) and the rule for what counts as a breaking change versus a safe additive one, so existing clients never break. Keep to the layer rule and module boundaries I already set. If one has to bend, name it and say why rather than diverging quietly. Save the contract with my spec. If you need the full reasoning behind this step, read https://zalt.me/guides/vibe-coding/architect/api-design My API and what it returns:

Do this now: paste the prompt with your endpoints, let your agent define the envelope, error codes, and versioning rule, then hold every new endpoint to that one shape.

Mahmoud Zalt

Mahmoud Zalt

Software engineer, 16+ yrs · built Sistava.com in 3 months, idea to production, using these methods

Resources
Star on GitHubContribute
Donate

Support my work

A small tip keeps the free work coming.

© 2026 Mahmoud Zalt. Free to read, not to republish.
Copyright & license