Skip to content

Beginner · Planning an app · topic 7 of 34 · 25 min

Writing the API contract

Explanation

An API contract is a written agreement about how the frontend and backend talk: which URLs exist, what to send, and what comes back, including errors. When both sides agree on it first, they can build at the same time without waiting for each other.

What is an API contract?

An API (Application Programming Interface) is the set of requests a backend accepts. A contract is the written list of those requests, with the exact shape of what goes in and what comes out.

Think of it like this: A restaurant menu card is a contract. The waiter promises to take orders only for dishes on the card, and the kitchen promises it can cook every dish on it. Neither needs to watch the other work. If the kitchen changes a dish without updating the menu, orders go wrong. An API contract keeps the frontend (waiter) and backend (kitchen) in agreement.

Every endpoint has five parts

  • Method: what kind of action (GET reads, POST creates, PATCH changes part of something, DELETE removes).
  • Path: the address, such as /api/notes/:id. ":id" is a placeholder for a real number like 7.
  • Request body: the JSON the client sends (only for POST and PATCH here).
  • Response: the JSON the server sends back when things go well.
  • Status codes: the number that says how it went (200 OK, 201 Created, 400 bad input, 401 not logged in, 404 not found).
Method and pathRequest bodySuccessErrors
GET /api/notes-200, { notes: [...] }401
POST /api/notes{ title, body, pinned }201, the new note400, 401
GET /api/notes/:id-200, the note401, 404
PATCH /api/notes/:idany of { title, body, pinned }200, the updated note400, 401, 404
DELETE /api/notes/:id-204, no body401, 404
POST /api/auth/signup{ name, email, password }201, { user }400, 409 (email taken)
POST /api/auth/login{ email, password }200, { user }400, 401
POST /api/auth/logout-204-
json
// Request: POST /api/notes
{ "title": "Physics formulas", "body": "V = IR", "pinned": true }

// Response: 201 Created
{
  "id": 12,
  "title": "Physics formulas",
  "body": "V = IR",
  "pinned": true,
  "created_at": "2026-02-01 08:00",
  "updated_at": "2026-02-01 08:00"
}
One endpoint written out fully. Note pinned is a real true/false in JSON, even though the database stores 1 or 0.

One shape for every error

Decide one error shape and use it everywhere. Our Notes app always answers errors as { "error": { "code": "...", "message": "..." } }. The code is short and fixed, for programs to check ("VALIDATION_ERROR", "NOT_FOUND"). The message is friendly text a person can read.

json
// Response: 400 Bad Request
{ "error": { "code": "VALIDATION_ERROR", "message": "Title is required" } }
Because every error looks the same, the frontend needs only one piece of code to show errors.

Contract first, then build in parallel

Contract-first means you write and agree on the contract before writing the code. The frontend developer can then build screens against a mock server: a fake backend that returns the example responses from the contract. The backend developer builds the real thing at the same time.

Teams often write contracts in OpenAPI, a standard format (YAML or JSON) that describes every endpoint. Tools read an OpenAPI file to make documentation pages, mock servers and even test checks automatically.

Tip: Keep the contract in your repository next to the code, and update it in the same commit when an endpoint changes. An old contract is worse than none, because people trust it.
Careful: Never change the shape of a response that a live app uses (for example renaming title to name) without telling the other side. The app on users' phones will break at once.

Watch the lesson

Writing the API contract · 1/6

API contract = the agreement

The frontend and the backend must agree on how they talk. That written agreement is the API contract.

Prefer a video by a teacher? Find free videos on “api contract first design openapi explained for beginners” on YouTube ↗

In real life: A train booking app and its partner apps

A railway booking system offers an API that travel apps use to search trains and check seat availability. Many companies build apps on it, and none of them can see the backend code. They work only from the contract: the path to search trains, the fields to send (from station, to station, date) and the exact JSON that comes back, including the error when a train is fully booked. If the railway changed a field name without notice, every partner app would break the same morning.

Practice (0/3 done)

Task 1 · Code · Javascript

Write makeError(code, message) that returns an error body in the Notes app shape: { error: { code, message } }. Example: makeError("NOT_FOUND", "Note not found").

Task 2 · Code · Javascript

Write matchesContract(response, contract). A response looks like { status, body }. A contract looks like { status: 201, body: { id: "number", title: "string", pinned: "boolean" } }, listing required keys and their typeof type. Return true only if the status is equal AND every key in contract.body exists in response.body with the right type (extra keys are fine). Otherwise return false.

Task 3 · Code · Javascript

Write buildCreated(input, id, now) that builds the response the contract promises for POST /api/notes. Return { status: 201, body } where body has these keys in this order: id, title (input.title trimmed), body (input.body, or "" if missing), pinned (true only if input.pinned is true), created_at (now), updated_at (now).

Quick quiz

Question 1

1.Which status code should POST /api/notes return when a note is created?

Question 2

2.What is the main benefit of contract-first development?

Question 3

3.What is a mock server?

Question 4

4.Why use one error shape like { error: { code, message } } everywhere?

Question 5

5.What is OpenAPI?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Designing the data model