The typical API development pattern: the backend gets coded, the code stabilizes, then someone writes docs, the docs drift out of sync, nobody maintains them.
Doc-first is the opposite: write the OpenAPI spec first, treat the spec as the source of truth, generate code and docs from the spec (or keep them in sync manually when generation isn’t possible). Projects where I’ve used this discipline turn out dramatically better.
This post covers the practical wins and how I set it up.
OpenAPI, quick refresher
OpenAPI (formerly Swagger) is a standard for describing REST APIs. YAML or JSON. Endpoints, request/response schemas, authentication, errors: it all goes in.
Basic example:
openapi: 3.0.3
info:
title: My API
version: 1.0.0
paths:
/users/{id}:
get:
summary: Get user by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id: { type: string }
name: { type: string }
email: { type: string }Readable, version controllable, machine-parseable for validation.
Benefit 1: design review before implementation
Traditional flow: backend implements an endpoint, frontend sees it, “this shape is wrong”, backend changes it. Two or three iterations.
Doc-first: the OpenAPI spec goes up in a PR. Frontend developer, backend developer, product manager all review. Once the spec is approved, implementation starts.
Upshot:
– Wrong field names get caught early
– Missing edge cases (pagination, filtering) show up in the spec
– Frontend development starts in parallel with backend (using a mock server)
On my projects spec review takes one to two hours. Skipping it costs a week.
Benefit 2: code generation
You can generate code automatically from the OpenAPI spec:
Backend models:
– openapi-generator-cli produces Go/Python/Node.js structs.
– When the spec changes, structs update automatically.
API client libraries:
– TypeScript client for the frontend (type-safe fetch calls).
– Swift package for iOS.
– Kotlin library for Android.
– Each platform gets its own native client.
Example:
openapi-generator-cli generate
-i openapi.yaml
-g typescript-axios
-o ./frontend/src/api-clientThe frontend developer gets typed functions:
const user = await api.users.getUser({ id: '123' });
// user: User typeAuto-generated, type-safe client instead of hand-rolled fetch calls.
Benefit 3: mock server (parallel development)
Generate a mock server from the OpenAPI spec. The frontend stops waiting for the backend to ship.
Tools:
– Prism: prism mock openapi.yaml, one command, mock server up.
– Stoplight Prism: CLI plus cloud versions.
– MockAPI: SaaS, mock through a web UI.
Frontend developer:
fetch('http://localhost:4010/users/123')
// Mock response: example data from specBackend developer builds the real endpoint in parallel. Because both work off the same spec, there’s minimal friction at integration time.
Benefit 4: documentation that’s always current
Biggest pain point with traditional flows: the docs don’t match the code. Six months later you notice nobody updated the docs.
In a doc-first approach:
- The spec lives in the code repo
- Every PR updates the spec too (or the reviewer asks for it)
- Generated client libraries regenerate on every build, stale code doesn’t compile
- Swagger UI / Redoc renders the spec in real time
Docs aren’t a “snapshot from one day”; they’re the live API surface.
Tool ecosystem
The OpenAPI tool ecosystem is strong:
Writing specs:
– Stoplight Studio: visual editor
– Swagger Editor: web-based
– VS Code OpenAPI extension
Rendering:
– Swagger UI: classic interactive docs
– Redoc: modern, cleaner
– Stoplight Elements: embeddable component
Validation:
– Spectral: lint rules for OpenAPI specs
– openapi-validator: schema conformance
Testing:
– Dredd: compares spec to actual API (contract testing)
– Postman: spec import, test collections
Mock:
– Prism: CLI mock server
– MockServer: advanced mock with recording
Practical workflow
My actual workflow:
1. Design phase (1 to 2 days):
– Spec the feature with the PM: endpoints, user journey
– Write the first OpenAPI draft
– Open it as a PR titled “[SPEC] User Management API v1”
2. Review phase (1 to 2 days):
– Frontend, backend, QA review
– Schema fields debated
– Edge cases added (error responses, pagination)
– PR merged
3. Parallel implementation (1 to 2 weeks):
– Backend implements the real endpoint
– Frontend builds against the auto-generated TypeScript client
– QA generates a Postman collection from the spec
4. Integration (1 to 2 days):
– Backend endpoint tested from the frontend
– Contract testing (Dredd) checks spec vs implementation
– If anything diverges, it’s a spec-vs-code debate (usually the spec wins, because it was reviewed)
5. Release:
– Swagger UI auto-generated
– Public API documentation site
– Client libraries published as versioned packages
This workflow adds about a week to the early design phase of a 3 to 5 week feature. But it cuts 2 to 3 weeks off integration bugs. Net gain: about 30% throughput.
Common anti-patterns
1. Writing the spec after the code. That’s not doc-first. Generic documentation buys you much less here.
2. Changing code without updating the spec. One or two months later the spec is stale, nobody trusts it. Takes team discipline.
3. Spec too simple. Only the happy path. Error responses and edge cases missing. Every response code should be in the spec.
4. Tooling overload. Ten different tools, none of them fully set up. Minimum: Swagger UI (docs) + Prism (mock) + openapi-generator (client libs).
Migration: moving an existing API to doc-first
Retrofitting an existing API into OpenAPI is a big job. Strategy:
Phase 1: spec the current version. Document every endpoint, update the implementation to match the spec where tests are missing.
Phase 2: new features go doc-first.
Phase 3: gradually move legacy endpoints into the spec.
A 6 to 12 month effort, but a good investment. Makes large APIs much easier to maintain.
OpenAPI 3.0 vs 3.1
Version choice:
- OpenAPI 3.0: mature, broad tool support. Most common.
- OpenAPI 3.1: compatible with JSON Schema Draft 2020, better schema features.
Write new projects in OpenAPI 3.1. Existing projects can stay on 3.0.
Security in OpenAPI
Auth mechanisms live in the spec:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
paths:
/users:
get:
security:
- bearerAuth: []
# ...Every endpoint’s security requirement is in the spec. Swagger UI gets an “Authorize” button for interactive testing.
Monorepo vs split
Where should the spec live?
Single repo (monorepo): openapi.yaml in the backend repo. Client libraries in a separate directory inside the monorepo.
Spec repo: a dedicated repo just for the API spec. Backend and clients consume it.
Monorepo is easier for small teams. Multi-team enterprises often need a separate spec repo to enforce discipline.
Bottom line
Doc-first API development is discipline-intensive but high leverage. Design review happens early, the frontend works in parallel, client libraries are auto-generated, docs stay current.
The OpenAPI ecosystem is mature. Initial setup is a one to two week job. After that, every new API feature takes two or three hours of spec writing, and saves two or three weeks of integration bugs. The ROI is positive.
Start small: spec one endpoint, render Swagger UI, do a review. If the feedback is positive, extend it across the whole API.