Skip to main content

/writing

Mocking the API Contract Before Implementing It

· 3 min read

When backend and frontend build the same feature, the frontend waits. Everyone agreed the API shape on a whiteboard, but until the endpoint returns something, nobody can wire the UI to it. So the frontend writes mocks, the mocks drift, and “we agreed on the shape” stops meaning much once the real thing lands looking slightly different.

I started shipping the contract before the implementation. The endpoint goes to production early, returns a realistic example payload, and serves the agreed OpenAPI shape before any real work happens behind it.

This is one piece of the dashboard’s integration layer. Contract-first mocks sit at the boundary between teams, before the codegen pipeline or the proxy layer ever see the spec.

The contract is the decision

The shape of an API is the part worth arguing about: field names, types, what is optional, how a list differs from a single item, how errors come back. Once those are settled, the implementation behind them is just engineering. The implementation can change later. The contract is what the frontend, the SDK consumers, the docs and the SLA all depend on.

Treating the contract as the output of the design phase changes the order of work. Design, build, expose becomes design, expose, build.

Alternatives considered

This meant rejecting three patterns the team had already tried.

Wait for the backend. The default. Frontend work blocks on backend work even when everyone agrees on the contract. That delay is the whole problem, and being patient about it does not make it smaller.

Frontend-local stubs. Everyone writes their own mock for whatever they need to render today. The stubs drift from each other and from reality, and by the time the real endpoint lands there are three code paths for the same data to reconcile.

Types only. Publish the TypeScript types from the spec and leave the endpoint for later. You can compile against types, but they do not return data. QA, integration tests and screenshots all still wait.

A mocked endpoint gives you what each of those was reaching for at once: a real URL, real types and realistic payloads, in production from day one.

Realistic examples beat empty stubs

An endpoint returning an empty list is technically a contract and practically useless. The frontend cannot tell whether the rendering is right, because the data does not look like data. QA cannot test edge cases, because there are none.

An endpoint returning a realistic payload is a different thing. It looks like what you will actually get. Schema generators consume it and docs tools render it as a sample response. The same examples end up in the spec, the mock and the documentation, from one source.

A marker for what is real

The catch is that a consumer cannot tell a real endpoint from a stub returning canned data. So each endpoint carried a small marker showing its implementation status. Mocked ones appeared as mocked in internal dashboards, and CI refused to call an endpoint done until the marker came off.

It did one boring job well. It made the difference between “returns 200” and “does what it says” visible to everyone.

What I learned

The delay between backend and frontend is real but mostly self-imposed. Ship the contract first, even as a mock, and the problem turns into scheduling. The frontend builds against the real URL, the backend implements at its own pace, and the day the implementation lands the frontend already works.