# API Documentation

## 1. Why 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.

## 2. OpenAPI: 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](diagrams/01-openapi-contract.svg)

## 3. Schema-First vs. Code-First Generation

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

| Approach | How it works | Risk |
|---|---|---|
| **Schema-first** | Write the OpenAPI YAML by hand (or in a design tool) *before* implementing the endpoint; the schema is the source of truth | Code can drift from the schema if nothing enforces the match at build/test time |
| **Code-first** | Annotate route handlers with decorators/comments; a generator derives the OpenAPI document from the code | The 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.

## 4. What 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

## 5. Keeping 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.

## 6. Versioned 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

```
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
```
