Engineering Notes
Home/Backend/API Design/API Documentation
Backend · API Design

API Documentation

Docs are part of the API. Write a machine-readable OpenAPI contract, choose schema-first or code-first generation, cover what every endpoint must document, and stop drift with contract tests in CI.

⚙️ Backend● Beginner⏱ 5 min read▶ 2 interactive🛠️ 2 exercises🎤 5 interview Q&As

🎯 What you'll learn

  • Why documentation is part of the API
  • OpenAPI as a machine-readable contract
  • Schema-first vs code-first
  • What each endpoint needs; contract testing and versioned docs

1Why Documentation Is Part of the API, Not an Afterthought

An API's real interface is not the code — it's what a consumer who has never seen your source can learn from the docs alone. Two APIs with identical implementations but different documentation are, from a client's perspective, different products: one is usable, the other requires reverse-engineering by trial and error. Documentation is the contract a client programs against, which is why it needs the same rigor as the code enforcing that contract.

2OpenAPI: a Machine-Readable Contract, Not Just Prose

The dominant standard for REST API documentation is OpenAPI (formerly Swagger) — a JSON/YAML document describing every endpoint, its parameters, request/response shapes, and status codes, in a format tools can parse:

yaml
openapi: 3.0.3
info:
  title: Orders API
  version: 1.2.0
paths:
  /orders/{id}:
    get:
      summary: Retrieve a single order
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Order found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: No order with this id
components:
  schemas:
    Order:
      type: object
      required: [id, status, total_cents]
      properties:
        id: { type: integer }
        status: { type: string, enum: [pending, confirmed, shipped, cancelled] }
        total_cents: { type: integer }

Because this is structured data, not free-form prose, tooling can generate an interactive explorer (Swagger UI, Redoc), typed client SDKs, and — critically — validate real requests/responses against the schema in tests (see section 5).

One OpenAPI file drives documentation UI, typed client SDKs, server validation and contract tests in CI
One OpenAPI file drives documentation UI, typed client SDKs, server validation and contract tests in CI

3Schema-First vs. Code-First Generation

Two opposing workflows produce the same OpenAPI document, with different failure modes:

ApproachHow it worksRisk
Schema-firstWrite the OpenAPI YAML by hand (or in a design tool) before implementing the endpoint; the schema is the source of truthCode can drift from the schema if nothing enforces the match at build/test time
Code-firstAnnotate route handlers with decorators/comments; a generator derives the OpenAPI document from the codeThe schema can only describe what the code's annotations say — a forgotten annotation silently produces incomplete docs, not a build failure

Neither approach is safe by construction — both need an explicit verification step (section 5) or they degrade into documentation nobody trusts, which is worse than no documentation at all because it actively misleads.

4What Every Endpoint's Documentation Must Cover

A documented endpoint that omits any of the following forces the consumer back into reading source code or guessing:

  • Every parameter — path, query, header, and body — with type, whether it's required, and any constraints (min/max, enum, format)
  • Every realistic response status code, not just the happy path — 200 and 400, 401, 404, 409, 422, 429 as applicable, each with its response shape
  • Authentication requirements — which scheme (API key, Bearer token, OAuth2 scope), and which scopes/permissions this specific endpoint needs (see backend/api-design/10-api_security for the auth mechanisms themselves)
  • Example request and response bodies — a schema alone rarely conveys shape as clearly as one concrete, realistic JSON example
  • Rate limit behavior, if the endpoint is limited (see backend/api-design/07-rate_limiting) — the limit, and what a 429 response looks like

5Keeping Docs From Drifting: Contract Testing

The single biggest failure mode of API documentation is silent drift — the code changes, the docs don't, and consumers build against a lie. The fix is to make the schema part of the test suite instead of a static artifact nobody re-checks:

ts
// A contract test: real responses are validated against the OpenAPI schema on every run
import { validateResponseAgainstSchema } from "./openapi-validator";

test("GET /orders/:id matches the documented schema", async () => {
  const response = await request(app).get("/orders/42");
  const result = validateResponseAgainstSchema("GET /orders/{id}", 200, response.body);
  expect(result.valid).toBe(true); // fails the build the moment code and docs disagree
});

Once this exists, a schema/implementation mismatch is a CI failure, not a support ticket filed by a confused consumer weeks later.

6Versioned Documentation

Docs for an API must be versioned exactly like the API itself (see backend/api-design/05-api_versioning) — a consumer pinned to v1 reading v2's documentation will implement against endpoints and shapes that don't exist for them. Most doc-hosting setups publish one rendered doc site per active API version, with the currently-recommended version clearly marked and deprecated versions explicitly labeled with their sunset date.

⚠️ Common Pitfalls

  1. Documenting only the 200 response. Consumers building real error handling need every status code the endpoint can actually return, not just the success case.
  2. Letting code-first annotations silently omit fields. A forgotten @ApiProperty() (or equivalent) produces a schema that's incomplete, not one that fails to build — nothing forces the gap to surface.
  3. No contract tests. Without section 5's validation step, "the docs match the code" is an assumption, not a guarantee, and it erodes the first time someone ships without updating both.
  4. Publishing one unversioned doc site. Consumers on an older API version have no way to know the docs they're reading describe a different contract than the one they integrated against.
  5. Treating examples as optional. A schema alone (type: string, format: uuid) is technically complete but far slower for a human to act on than one realistic example value.

📋 Quick Reference

text
OpenAPI/Swagger    machine-readable contract: paths, schemas, responses, auth
Schema-first        write the spec, then implement to match it
Code-first          derive the spec from annotated code
Must document        every param, every realistic status code, auth requirement, example
Contract tests       validate real responses against the schema in CI — catches drift
Versioned docs        one doc site per active API version, deprecated ones labeled

🧠 Key takeaways

  • OpenAPI describes paths, params, schemas, auth and errors in a machine-readable way.
  • Schema-first: design and review the contract first; code-first: generate from annotations. Either way, one source of truth.
  • Document auth, params, request/response examples, every error, rate limits, pagination.
  • Prevent drift with contract tests (Schemathesis, Dredd, Pact) and generated clients.

🎤 Interview Q&A

Questions interviewers ask about this topic. Answer out loud first, then open a card to compare.

Q1What makes API documentation good?core▾

An accurate reference (endpoints, parameters, schemas, errors), authentication guide, getting-started tutorial, runnable examples and SDK snippets, changelog and versioning policy, rate limit info, and a try-it console.

Follow-ups interviewers ask
  • Which is most often missing? Error documentation and realistic examples.
Q2What is OpenAPI and how is it used?core▾

A machine-readable specification (YAML/JSON) of an HTTP API. It powers docs (Swagger UI, Redoc), client/server code generation, request validation, mocks, contract testing and breaking-change detection.

Follow-ups interviewers ask
  • OpenAPI vs Swagger? Swagger was the original name; OpenAPI is the standard, Swagger the tooling brand.
Q3Code-first vs design-first API development?senior▾

Design-first: write the OpenAPI spec, review it with consumers, then implement; better API design and parallel work. Code-first: generate the spec from annotations; faster for small teams but design gets less scrutiny.

Follow-ups interviewers ask
  • How do you keep code and spec in sync? Generate one from the other and validate in CI.
Q4How do you document asynchronous/event APIs?core▾

With AsyncAPI, which describes channels, messages and schemas for Kafka, AMQP, WebSockets and more, similar to OpenAPI for HTTP.

Follow-ups interviewers ask
  • Also useful? A schema registry and an event catalog.
Q5How do you keep docs from going stale?core▾

Generate reference docs from the source of truth, test examples in CI, version docs with the API, and include docs in the definition of done for API changes.

Follow-ups interviewers ask
  • What's docs-as-code? Docs in the repo, reviewed in PRs and built in CI.

🛠️ Practice exercises

Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.

✅ Check yourself

Answer the questions — feedback is instant.

1. Main advantage of schema-first?
Design first.
2. How do you keep docs from drifting?
Automate it.
3. Which is usually missing from weak API docs?
Document failures.
4. OpenAPI enables…
Machine-readable.