REST API Documentation
Publish beautiful, interactive API docs from your OpenAPI spec using Scalar, Redoc, and Swagger UI
The 5 Pillars of Great API Documentation
Great API documentation is the difference between developers adopting your API in hours vs abandoning it in frustration. It combines five complementary content types:
| Content Type | Purpose | Example |
|---|---|---|
| Reference | Complete endpoint list with parameters, schemas, examples | Swagger UI / Redoc / Scalar |
| Guides | Explain concepts and design decisions | "Authentication Overview", "Pagination Guide" |
| Tutorials | Step-by-step for a specific goal | "Build Your First Order in 5 Minutes" |
| Code Examples | Copy-paste snippets in multiple languages | cURL, Node.js, Python, Ruby |
| Changelog | What changed, when, and what to do about it | CHANGELOG.md with migration notes |
OpenAPI as the Single Source of Truth
Write your OpenAPI 3.1 spec once — all documentation tools, SDK generators, mock servers, and test suites derive from it. This eliminates documentation drift where prose docs and actual API behaviour diverge.
# Directory structure: API-first
my-api/
├── openapi.yaml # Single source of truth
├── schemas/
│ ├── user.yaml # JSON Schema $ref'd from openapi.yaml
│ └── order.yaml
├── docs/
│ ├── guides/ # Concept guides (Markdown)
│ └── tutorials/ # Step-by-step tutorials
└── src/ # Implementation
Swagger UI
The original OpenAPI UI — "try it out" functionality lets users test endpoints directly from the browser. Best for APIs consumed by developers who want to experiment.
npm install swagger-ui-express yaml
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yaml');
const fs = require('fs');
const app = express();
const spec = YAML.parse(fs.readFileSync('./openapi.yaml', 'utf8'));
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec, {
customCss: '.swagger-ui .topbar { display: none }',
customSiteTitle: 'My API Reference',
swaggerOptions: {
persistAuthorization: true, // keep auth token between page refreshes
deepLinking: true, // shareable URLs to specific endpoints
displayRequestDuration: true // show response time in UI
}
}));
// Also serve the raw OpenAPI spec (for SDK generators, Postman, etc.)
app.get('/openapi.yaml', (req, res) => {
res.set('Content-Type', 'application/yaml');
res.send(fs.readFileSync('./openapi.yaml'));
});
Redoc
Redoc generates a beautiful 3-panel read-only reference (navigation, endpoint detail, code samples). Best for consumer-facing documentation where you want polished, professional appearance.
npm install redoc-express
const redoc = require('redoc-express');
app.get('/reference', redoc({
title: 'My API Reference',
specUrl: '/openapi.yaml',
redocOptions: {
theme: { colors: { primary: { main: '#1e40af' } } },
hideDownloadButton: false,
expandResponses: '200,201',
requiredPropsFirst: true,
sortPropsAlphabetically: false
}
}));
To generate a standalone static HTML file (for hosting on S3/GitHub Pages):
npx @redocly/cli build-docs openapi.yaml --output docs/index.html
Scalar (Rising in 2026)
Scalar is the fastest-growing API documentation tool in 2026 — modern design, dark mode, interactive "API Client" playground, and zero-config setup. Increasingly chosen over Swagger UI for new projects.
<!-- Serve Scalar as a self-contained HTML page -->
app.get('/reference', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>My API Reference</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<script
id="api-reference"
data-url="/openapi.yaml"
data-configuration='{"theme":"purple","defaultHttpClient":{"targetKey":"node","clientKey":"fetch"}}'
></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
</body>
</html>
`);
});
Stoplight
Stoplight is an API design platform — collaborative OpenAPI editor + documentation + style guide linting. Best for teams that want an API-first workflow with governance.
- Stoplight Studio — visual OpenAPI editor (no YAML knowledge required)
- Stoplight Spectral — OpenAPI linting with custom rules
- Stoplight Prism — mock server from OpenAPI spec
# Lint your OpenAPI spec with Spectral
npm install -g @stoplight/spectral-cli
spectral lint openapi.yaml --ruleset .spectral.yaml
# .spectral.yaml
extends: ["spectral:oas"]
rules:
operation-operationId: error
operation-tag-defined: warn
info-contact: warn
Tool Comparison
| Tool | Type | Try-it-out | Dark Mode | Best For |
|---|---|---|---|---|
| Scalar | Hosted/self | ✅ API Client | ✅ | Modern developer experience, new projects |
| Swagger UI | Self-hosted | ✅ | Limited | Quick setup, familiar to all devs |
| Redoc | Self-hosted | ❌ Read-only | ✅ | Polished consumer-facing reference |
| Stoplight | Platform | ✅ | ✅ | Team API design + governance |
| Readme.com | SaaS | ✅ | ✅ | Developer portal + changelog + guides |
Docs-as-Code
Treat your API documentation like code: version-controlled in Git, reviewed in PRs, automatically tested and deployed.
# Validate OpenAPI spec in CI
npx @stoplight/spectral-cli lint openapi.yaml
# Generate client SDKs on every release
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o sdk/typescript
# Check for breaking changes
npx @redocly/cli diff openapi-main.yaml openapi-branch.yaml
CI/CD Publish Pipeline
# .gitlab-ci.yml — publish docs to GitLab Pages on every main merge
docs:
stage: deploy
image: node:20
script:
- npx @stoplight/spectral-cli lint openapi.yaml # lint first
- npx @redocly/cli build-docs openapi.yaml --output public/index.html
- cp openapi.yaml public/openapi.yaml
artifacts:
paths:
- public
pages: true
only:
- main
Changelog Best Practices
Follow Keep a Changelog format and Semantic Versioning:
# CHANGELOG.md
## [2.4.0] - 2026-05-13
### Added
- POST /orders now accepts an `idempotency_key` field
- GET /users supports `?status=active|inactive` filter
### Changed
- GET /orders now returns `total_cents` (integer) instead of `total` (string)
Migration: multiply old `total` by 100, or use new field directly
### Deprecated
- GET /v1/users — use /v2/users instead. Sunset: 2026-12-31
### Removed
- DELETE /v1/orders/:id — use /v2/orders/:id (same behaviour, better error messages)
Publish the changelog as part of your API documentation and link to it from your Deprecation Link header. For full deprecation strategy, see our API Deprecation guide.