Documenting APIs (OpenAPI/Swagger)
An undocumented API is one nobody can use without reading your source. OpenAPI (formerly Swagger) is the industry-standard, machine-readable format for describing a REST API — its endpoints, parameters, request/response shapes, and auth. From a single OpenAPI document you get interactive docs, client SDKs, server stubs, and contract tests. This page shows what an OpenAPI spec looks like and how to serve interactive docs from an Express app.
What OpenAPI gives you
Interactive docs — Swagger UI / Redoc let users explore and try endpoints in the browser.
Client SDK generation — generate typed clients for TypeScript, Python, Go… from the spec.
Server stubs & validation — validate requests/responses against the schema at runtime.
A single source of truth — the contract, versioned alongside your code.
A minimal OpenAPI document
openapi.js
export const openapiSpec = {
openapi: '3.0.3',
info: { title: 'Tasks API', version: '1.0.0' },
paths: {
'/tasks': {
get: {
summary: 'List tasks',
responses: {
200: {
description: 'An array of tasks',
content: {
'application/json': {
schema: { type: 'array', items: { $ref: '#/components/schemas/Task' } },
},
},
},
},
},
post: {
summary: 'Create a task',
requestBody: {
required: true,
content: {
'application/json': {
schema: { $ref: '#/components/schemas/NewTask' },
},
},
},
responses: { 201: { description: 'Created' }, 422: { description: 'Validation failed' } },
},
},
},
components: {
schemas: {
Task: {
type: 'object',
properties: {
id: { type: 'integer' },
title: { type: 'string' },
done: { type: 'boolean' },
},
required: ['id', 'title', 'done'],
},
NewTask: {
type: 'object',
properties: { title: { type: 'string', minLength: 1 } },
required: ['title'],
},
},
},
}Serving interactive docs in Express
import swaggerUi from 'swagger-ui-express'
import { openapiSpec } from './openapi.js'
// Interactive docs at /docs:
app.use('/docs', swaggerUi.serve, swaggerUi.setup(openapiSpec))
// Raw spec for codegen tools / other consumers:
app.get('/openapi.json', (req, res) => res.json(openapiSpec))Open http://localhost:3000/docs → Swagger UI renders every endpoint with "Try it out" buttons, request/response schemas, and example payloads.
Generating the spec instead of hand-writing it
Approach | Tool | Idea |
|---|---|---|
JSDoc comments |
| Annotate routes; build the spec from comments |
From Zod schemas |
| Reuse validation schemas as the doc source |
Spec-first | Swagger Editor | Write the YAML first, generate stubs/clients |
From types |
| Derive routes + spec from TypeScript types |
Document what clients actually need
Every endpoint: method, path, summary, and parameters.
Request body schema with required fields and examples.
All response statuses — success and the error envelope.
Authentication scheme (bearer token, API key) under
securitySchemes.Pagination, filtering, and rate-limit behavior.