API documentation
Guide agents to update OpenAPI alongside route implementations: path params, request schemas, auth, and error bodies must share a single source; examples should run; error codes should match problem+json (or your envelope); prevent doc drift.
This page gives Agents a complete API documentation reference: Swagger UI integration configuration (Express/FastAPI), JSDoc/docstring auto-generated documentation examples, CHANGELOG version recording format, curl request/response examples, and contract testing implementation.
Each public endpoint includes a runnable curl example and a typical failure example; pagination and filter parameters document defaults and caps; versioning strategy (URL prefix) is explained in an early chapter; deprecated APIs use deprecated: true dual marking.
- CI runs contract tests or schema diff, blocking merges where code changed but YAML wasn't updated.
Swagger UI integration configuration
Express + swagger-ui-express integration:
// app.ts — Express Swagger UI integration
import express from 'express'
import swaggerUi from 'swagger-ui-express'
import YAML from 'yamljs'
import path from 'path'
const app = express()
const swaggerDoc = YAML.load(path.join(__dirname, '../openapi.yaml'))
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDoc, {
swaggerOptions: {
persistAuthorization: true,
filter: true,
displayRequestDuration: true,
},
customCss: '.swagger-ui .topbar { display: none }',
}))
// Also serve raw JSON (for CI schema diff)
app.get('/openapi.json', (_req, res) => res.json(swaggerDoc))
JSDoc auto-generate API documentation comments:
// routes/items.ts
/**
* @openapi
* /v1/items/{itemId}:
* get:
* tags: [Items]
* summary: Get a single item
* operationId: getV1ItemById
* parameters:
* - in: path
* name: itemId
* required: true
* schema: { type: string, format: uuid }
* responses:
* '200':
* description: Item details
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Item'
* '404':
* $ref: '#/components/responses/NotFoundProblem'
* security:
* - bearerAuth: []
*/
router.get('/:itemId', authenticate, async (req, res, next) => {
try {
const item = await itemService.findById(req.params.itemId)
if (!item) return res.status(404).json({ type: 'not-found', status: 404 })
res.json(item)
} catch (err) { next(err) }
})
pathsmust match real mount prefixes;serversaligns with gateway strip rules.requestBody/responsesmust referencecomponents.schemas— no copy-paste drift.
curl examples, CHANGELOG, and contract testing
Complete curl examples (success + failure):
# Create item (success)
curl -sS -X POST "https://api.example.com/v1/items" -H "Authorization: Bearer <ACCESS_TOKEN>" -H "Content-Type: application/json" -H "Idempotency-Key: req-abc123" -d '{"name":"Widget","price":9.99,"sku":"WGT-001"}'
# 200 response
{
"id": "01HX3K2ZF0GQ9PBEM7NW4Y5V6A",
"name": "Widget",
"price": 9.99,
"sku": "WGT-001",
"createdAt": "2026-04-11T08:00:00Z"
}
# 422 validation failure
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation Error",
"status": 422,
"errors": [
{ "field": "price", "code": "must_be_positive", "message": "price must be greater than 0" }
]
}
API CHANGELOG format (CHANGELOG.md):
## [2026-04-11] v2.3.0
### Added
- `GET /v2/items` supports `filter[category]` parameter filtering
### Changed
- `POST /v1/orders` response adds `estimatedDelivery` field (backward compatible)
### Deprecated
- `GET /v1/items/{id}/details` — please migrate to `GET /v2/items/{id}`
Will be removed on 2026-10-01 (`deprecated: true` marked in OpenAPI)
### Breaking (v2.0.0, 2026-01-01)
- Removed `POST /v1/auth/token`, unified to `/v2/auth/token`
- Error body changed from `{"error":"..."}` to RFC 7807 problem+json
Contract testing (prevent doc/implementation drift):
// tests/contract/items.contract.test.ts
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
import openApiSpec from '../../openapi.json'
import { app } from '../../src/app'
import supertest from 'supertest'
const ajv = new Ajv({ allErrors: true })
addFormats(ajv)
test('GET /v1/items/:id response matches OpenAPI schema', async () => {
const res = await supertest(app)
.get('/v1/items/01HX3K2ZF0GQ9PBEM7NW4Y5V6A')
.set('Authorization', 'Bearer test-token')
.expect(200)
const schema = openApiSpec.components.schemas.Item
const valid = ajv.validate(schema, res.body)
expect(valid).toBe(true)
if (!valid) console.error(ajv.errors)
})
Maintenance flow
Main line from code change to published docs; agents can expand each node into checklists (diff scope, reviewers, release window).
[ Route/handler change: path, params, auth, response models ]
|
v
[ Update OpenAPI: paths, components, examples, deprecated ]
|
v
[ Examples + errors: curl/SDK, Problem bodies, error table anchors ]
|
v
[ CI: schema diff / contract tests / breaking-change detection ]
|
v
[ Release: notes, SDK regen, external developer comms ]
operationId and slug preview
Sidebars, anchor URLs, or static generators often turn operationId into kebab-case slugs. The tool below previews common rules (collaboration aid, not a language spec). If operationId is empty, we suggest camelCase from HTTP method + path, then derive the slug.
Preview
Slug: insert hyphens at camelCase / snake_case boundaries and lowercase; path-derived ids turn {param} into PascalCase segments appended after the verb.
SKILL snippet
---
name: api-documentation
description: Keep OpenAPI aligned with implementation and complete examples
---
# Rules
- paths / operationId 1:1 correspond to route implementation
- requestBody / responses reference components.schemas, no inline duplicate definitions
- Each endpoint includes curl examples (success + typical failure), errors use RFC 7807 problem+json
- Deprecated endpoints: operationId adds deprecated:true + CHANGELOG Deprecated entry
- CI runs contract tests: use Ajv to verify real responses match OpenAPI schema
# Steps
1. Read existing openapi.yaml and route implementation, find diffs
2. Update paths: add/modify operationId, parameters, requestBody, responses
3. Update components/schemas: add or modify schema, no inline repetition
4. Complete examples: at least one success + one failure curl example per endpoint
5. Update CHANGELOG.md: group as Added/Changed/Deprecated/Breaking
6. Run contract tests: npx jest tests/contract/ confirm no drift
7. Swagger UI accessible: GET /api-docs renders correctly