api-docs-generator
API Docs Generator
Generate comprehensive, developer-friendly API documentation automatically.
Core Workflow
- Scan routes: Find all API route definitions
- Extract schemas: Request/response types, params
- Generate docs: Markdown/HTML documentation
- Add examples: Request/response examples
- Document errors: Error codes and handling
- Create guides: Authentication, getting started
Documentation Structure
docs/
├── api/
│ ├── index.md # API overview
│ ├── authentication.md # Auth guide
│ ├── errors.md # Error reference
│ ├── rate-limiting.md # Rate limit info
│ └── endpoints/
│ ├── users.md
│ ├── products.md
│ └── orders.md
├── guides/
│ ├── getting-started.md
│ ├── pagination.md
│ └── webhooks.md
└── sdks/
├── javascript.md
├── python.md
└── curl.md
Generator Script
// scripts/generate-api-docs.ts
import * as fs from "fs";
import * as path from "path";
interface RouteInfo {
method: string;
path: string;
name: string;
description?: string;
params?: ParamInfo[];
queryParams?: ParamInfo[];
requestBody?: SchemaInfo;
responses?: ResponseInfo[];
auth?: boolean;
tags?: string[];
}
interface ParamInfo {
name: string;
type: string;
required: boolean;
description?: string;
example?: string;
}
interface SchemaInfo {
type: string;
properties?: Record<string, PropertyInfo>;
required?: string[];
example?: object;
}
interface PropertyInfo {
type: string;
description?: string;
example?: unknown;
enum?: string[];
format?: string;
}
interface ResponseInfo {
status: number;
description: string;
schema?: SchemaInfo;
example?: object;
}
interface DocsOptions {
title: string;
baseUrl: string;
version: string;
outputDir: string;
format: "markdown" | "html" | "docusaurus";
}
function generateApiDocs(routes: RouteInfo[], options: DocsOptions): void {
const { outputDir } = options;
// Create directories
fs.mkdirSync(path.join(outputDir, "api", "endpoints"), { recursive: true });
fs.mkdirSync(path.join(outputDir, "guides"), { recursive: true });
// Generate overview
generateOverview(options);
// Generate auth docs
generateAuthDocs(options);
// Generate error docs
generateErrorDocs(options);
// Group routes by resource
const groupedRoutes = groupRoutesByResource(routes);
// Generate endpoint docs
for (const [resource, resourceRoutes] of Object.entries(groupedRoutes)) {
const content = generateEndpointDoc(resource, resourceRoutes, options);
const filePath = path.join(outputDir, "api", "endpoints", `${resource}.md`);
fs.writeFileSync(filePath, content);
}
// Generate getting started guide
generateGettingStarted(routes, options);
}
function generateEndpointDoc(
resource: string,
routes: RouteInfo[],
options: DocsOptions
): string {
const lines: string[] = [];
// Header
lines.push(`# ${capitalize(resource)}`);
lines.push("");
lines.push(`Endpoints for managing ${resource}.`);
lines.push("");
// Table of contents
lines.push("## Endpoints");
lines.push("");
lines.push("| Method | Endpoint | Description |");
lines.push("|--------|----------|-------------|");
for (const route of routes) {
lines.push(
`| \`${route.method}\` | \`${route.path}\` | ${route.description || route.name} |`
);
}
lines.push("");
// Detailed documentation for each endpoint
for (const route of routes) {
lines.push(generateEndpointSection(route, options));
lines.push("");
}
return lines.join("\n");
}
function generateEndpointSection(
route: RouteInfo,
options: DocsOptions
): string {
const lines: string[] = [];
const anchor = route.name.toLowerCase().replace(/\s+/g, "-");
// Endpoint header
lines.push(`## ${route.name} {#${anchor}}`);
lines.push("");
lines.push(
`<span class="method method-${route.method.toLowerCase()}">${route.method}</span> \`${route.path}\``
);
lines.push("");
if (route.description) {
lines.push(route.description);
lines.push("");
}
// Authentication
if (route.auth) {
lines.push("### Authentication");
lines.push("");
lines.push("This endpoint requires authentication. Include the Bearer token in the Authorization header.");
lines.push("");
}
// Path parameters
if (route.params?.length) {
lines.push("### Path Parameters");
lines.push("");
lines.push("| Parameter | Type | Required | Description |");
lines.push("|-----------|------|----------|-------------|");
for (const param of route.params) {
lines.push(
`| \`${param.name}\` | ${param.type} | ${param.required ? "Yes" : "No"} | ${param.description || "-"} |`
);
}
lines.push("");
}
// Query parameters
if (route.queryParams?.length) {
lines.push("### Query Parameters");
lines.push("");
lines.push("| Parameter | Type | Required | Default | Description |");
lines.push("|-----------|------|----------|---------|-------------|");
for (const param of route.queryParams) {
lines.push(
`| \`${param.name}\` | ${param.type} | ${param.required ? "Yes" : "No"} | ${param.example || "-"} | ${param.description || "-"} |`
);
}
lines.push("");
}
// Request body
if (route.requestBody) {
lines.push("### Request Body");
lines.push("");
lines.push("```json");
lines.push(JSON.stringify(route.requestBody.example || {}, null, 2));
lines.push("```");
lines.push("");
if (route.requestBody.properties) {
lines.push("| Field | Type | Required | Description |");
lines.push("|-------|------|----------|-------------|");
for (const [name, prop] of Object.entries(route.requestBody.properties)) {
const required = route.requestBody.required?.includes(name)
? "Yes"
: "No";
lines.push(
`| \`${name}\` | ${prop.type} | ${required} | ${prop.description || "-"} |`
);
}
lines.push("");
}
}
// Responses
lines.push("### Responses");
lines.push("");
const responses = route.responses || [
{ status: 200, description: "Successful response" },
{ status: 400, description: "Bad request" },
{ status: 401, description: "Unauthorized" },
{ status: 404, description: "Not found" },
];
for (const response of responses) {
lines.push(`#### ${response.status} ${response.description}`);
lines.push("");
if (response.example) {
lines.push("```json");
lines.push(JSON.stringify(response.example, null, 2));
lines.push("```");
lines.push("");
}
}
// Example request
lines.push("### Example Request");
lines.push("");
lines.push("```bash");
lines.push(generateCurlExample(route, options));
lines.push("```");
lines.push("");
return lines.join("\n");
}
function generateCurlExample(route: RouteInfo, options: DocsOptions): string {
const parts: string[] = ["curl"];
parts.push(`-X ${route.method}`);
let url = `${options.baseUrl}${route.path}`;
url = url.replace(/:(\w+)/g, "{$1}");
parts.push(`"${url}"`);
if (["POST", "PUT", "PATCH"].includes(route.method)) {
parts.push('-H "Content-Type: application/json"');
}
if (route.auth) {
parts.push('-H "Authorization: Bearer YOUR_TOKEN"');
}
if (route.requestBody?.example) {
parts.push(`-d '${JSON.stringify(route.requestBody.example)}'`);
}
return parts.join(" \\\n ");
}
function generateOverview(options: DocsOptions): void {
const content = `# ${options.title} API Reference
Version: ${options.version}
Base URL: \`${options.baseUrl}\`
## Overview
Welcome to the ${options.title} API documentation. This API provides programmatic access to [describe your service].
## Quick Links
- [Authentication](./authentication.md)
- [Error Handling](./errors.md)
- [Rate Limiting](./rate-limiting.md)
## Endpoints
| Resource | Description |
|----------|-------------|
| [Users](./endpoints/users.md) | User management |
| [Products](./endpoints/products.md) | Product catalog |
| [Orders](./endpoints/orders.md) | Order processing |
## SDKs & Libraries
- [JavaScript/TypeScript](../sdks/javascript.md)
- [Python](../sdks/python.md)
- [cURL Examples](../sdks/curl.md)
## Support
If you have questions or need help, please:
- Check the [FAQ](../guides/faq.md)
- Open an issue on GitHub
- Contact support@example.com
`;
fs.writeFileSync(path.join(options.outputDir, "api", "index.md"), content);
}
function generateAuthDocs(options: DocsOptions): void {
const content = `# Authentication
The ${options.title} API uses Bearer token authentication.
## Getting an Access Token
### Login
\`\`\`bash
curl -X POST "${options.baseUrl}/auth/login" \\
-H "Content-Type: application/json" \\
-d '{"email": "user@example.com", "password": "your-password"}'
\`\`\`
Response:
\`\`\`json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600,
"tokenType": "Bearer"
}
\`\`\`
## Using the Token
Include the token in the Authorization header of all authenticated requests:
\`\`\`bash
curl -X GET "${options.baseUrl}/users" \\
-H "Authorization: Bearer YOUR_TOKEN"
\`\`\`
## Token Expiration
Tokens expire after 1 hour. When a token expires, you'll receive a 401 response:
\`\`\`json
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "Your access token has expired"
}
}
\`\`\`
Refresh your token using the refresh endpoint:
\`\`\`bash
curl -X POST "${options.baseUrl}/auth/refresh" \\
-H "Content-Type: application/json" \\
-d '{"refreshToken": "YOUR_REFRESH_TOKEN"}'
\`\`\`
## API Keys
For server-to-server communication, you can use API keys:
\`\`\`bash
curl -X GET "${options.baseUrl}/users" \\
-H "X-API-Key: YOUR_API_KEY"
\`\`\`
Generate API keys in your dashboard under Settings > API Keys.
`;
fs.writeFileSync(
path.join(options.outputDir, "api", "authentication.md"),
content
);
}
function generateErrorDocs(options: DocsOptions): void {
const content = `# Error Handling
The API uses conventional HTTP status codes and returns errors in a consistent format.
## Error Response Format
\`\`\`json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {
"field": ["Specific error for this field"]
},
"trace_id": "abc123"
}
}
\`\`\`
## HTTP Status Codes
| Code | Description |
|------|-------------|
| 200 | OK - Request succeeded |
| 201 | Created - Resource created successfully |
| 204 | No Content - Request succeeded, no content returned |
| 400 | Bad Request - Invalid request data |
| 401 | Unauthorized - Missing or invalid authentication |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Resource already exists |
| 422 | Unprocessable Entity - Validation error |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Server error |
## Error Codes
### Validation Errors
| Code | Description |
|------|-------------|
| \`VALIDATION_ERROR\` | Request body validation failed |
| \`INVALID_FORMAT\` | Field format is invalid |
| \`REQUIRED_FIELD\` | Required field is missing |
### Authentication Errors
| Code | Description |
|------|-------------|
| \`UNAUTHORIZED\` | No authentication provided |
| \`INVALID_TOKEN\` | Token is invalid or malformed |
| \`TOKEN_EXPIRED\` | Token has expired |
| \`INSUFFICIENT_PERMISSIONS\` | User lacks required permissions |
### Resource Errors
| Code | Description |
|------|-------------|
| \`NOT_FOUND\` | Resource doesn't exist |
| \`ALREADY_EXISTS\` | Resource already exists |
| \`CONFLICT\` | Operation conflicts with current state |
### Rate Limiting
| Code | Description |
|------|-------------|
| \`RATE_LIMIT_EXCEEDED\` | Too many requests |
When rate limited, check the response headers:
\`\`\`
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000
\`\`\`
## Handling Errors
\`\`\`typescript
try {
const response = await api.get('/users');
} catch (error) {
if (error.response) {
switch (error.response.status) {
case 401:
// Redirect to login
break;
case 403:
// Show permission denied
break;
case 404:
// Show not found
break;
case 429:
// Implement retry with backoff
break;
default:
// Show generic error
}
}
}
\`\`\`
`;
fs.writeFileSync(path.join(options.outputDir, "api", "errors.md"), content);
}
function generateGettingStarted(
routes: RouteInfo[],
options: DocsOptions
): void {
const content = `# Getting Started
This guide will help you make your first API request.
## Prerequisites
- An API key or user account
- A tool to make HTTP requests (curl, Postman, or your preferred HTTP client)
## Step 1: Get Your API Credentials
1. Sign up for an account at [example.com](https://example.com)
2. Navigate to Settings > API Keys
3. Generate a new API key
## Step 2: Make Your First Request
Let's fetch a list of users:
\`\`\`bash
curl -X GET "${options.baseUrl}/users" \\
-H "Authorization: Bearer YOUR_TOKEN"
\`\`\`
You should receive a response like:
\`\`\`json
{
"success": true,
"data": [
{
"id": "user_123",
"name": "John Doe",
"email": "john@example.com"
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 1
}
}
\`\`\`
## Step 3: Create a Resource
\`\`\`bash
curl -X POST "${options.baseUrl}/users" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer YOUR_TOKEN" \\
-d '{
"name": "Jane Doe",
"email": "jane@example.com"
}'
\`\`\`
## Next Steps
- Read the [Authentication Guide](../api/authentication.md)
- Explore the [API Reference](../api/index.md)
- Check out [Error Handling](../api/errors.md)
- Try the [Postman Collection](./postman.md)
`;
fs.writeFileSync(
path.join(options.outputDir, "guides", "getting-started.md"),
content
);
}
function groupRoutesByResource(
routes: RouteInfo[]
): Record<string, RouteInfo[]> {
const groups: Record<string, RouteInfo[]> = {};
for (const route of routes) {
const parts = route.path.split("/").filter(Boolean);
const resource = parts[0] || "api";
if (!groups[resource]) {
groups[resource] = [];
}
groups[resource].push(route);
}
return groups;
}
function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
Example Generated Documentation
users.md
# Users
Endpoints for managing users.
## Endpoints
| Method | Endpoint | Description |
| -------- | ----------------- | ------------------- |
| `GET` | `/api/users` | List all users |
| `GET` | `/api/users/:id` | Get user by ID |
| `POST` | `/api/users` | Create new user |
| `PUT` | `/api/users/:id` | Update user |
| `DELETE` | `/api/users/:id` | Delete user |
## List Users {#list-users}
<span class="method method-get">GET</span> `/api/users`
Retrieve a paginated list of users.
### Authentication
This endpoint requires authentication. Include the Bearer token in the Authorization header.
### Query Parameters
| Parameter | Type | Required | Default | Description |
| --------- | ------- | -------- | ------- | ------------------------ |
| `page` | integer | No | 1 | Page number |
| `limit` | integer | No | 10 | Items per page (max 100) |
| `sort` | string | No | - | Sort field |
| `order` | string | No | desc | Sort order (asc/desc) |
### Responses
#### 200 OK
```json
{
"success": true,
"data": [
{
"id": "user_abc123",
"name": "John Doe",
"email": "john@example.com",
"role": "user",
"createdAt": "2024-01-15T10:30:00Z"
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 156,
"total_pages": 16
}
}
401 Unauthorized
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
}
Example Request
curl -X GET "https://api.example.com/users?page=1&limit=10" \
-H "Authorization: Bearer YOUR_TOKEN"
Create User {#create-user}
POST /api/users
Create a new user account.
Authentication
This endpoint requires authentication. Include the Bearer token in the Authorization header.
Request Body
{
"name": "John Doe",
"email": "john@example.com",
"role": "user"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | User's full name |
email |
string | Yes | User's email (must be unique) |
role |
string | No | User role (user, admin) |
Responses
201 Created
{
"success": true,
"data": {
"id": "user_xyz789",
"name": "John Doe",
"email": "john@example.com",
"role": "user",
"createdAt": "2024-01-15T10:30:00Z"
}
}
400 Bad Request
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"email": ["Invalid email format"]
}
}
}
Example Request
curl -X POST "https://api.example.com/users" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"name": "John Doe", "email": "john@example.com"}'
## CLI Script
```typescript
#!/usr/bin/env node
// scripts/docs-gen.ts
import * as fs from "fs";
import { program } from "commander";
program
.name("docs-gen")
.description("Generate API documentation from routes")
.option("-f, --framework <type>", "Framework (express|nextjs|fastify)", "express")
.option("-s, --source <path>", "Source directory", "./src")
.option("-o, --output <path>", "Output directory", "./docs")
.option("-t, --title <name>", "API title", "My API")
.option("-v, --version <version>", "API version", "1.0.0")
.option("-b, --base-url <url>", "Base URL", "https://api.example.com")
.option("--format <type>", "Output format (markdown|html|docusaurus)", "markdown")
.parse();
const options = program.opts();
async function main() {
const routes = await scanRoutes(options.framework, options.source);
generateApiDocs(routes, {
title: options.title,
baseUrl: options.baseUrl,
version: options.version,
outputDir: options.output,
format: options.format,
});
console.log(`Generated documentation in ${options.output}`);
}
main();
Best Practices
- Keep docs updated: Regenerate docs on route changes
- Include examples: Show real request/response examples
- Document errors: List all possible error codes
- Add authentication guide: Explain how to authenticate
- Use consistent format: Follow same structure for all endpoints
- Version your docs: Match doc versions to API versions
- Make it searchable: Include table of contents and anchors
- Provide SDKs: Link to client libraries and code examples
Output Checklist
- API overview with quick links
- Authentication guide
- Error handling reference
- Endpoint documentation per resource
- Path and query parameters documented
- Request body schemas with field descriptions
- Response examples for all status codes
- cURL examples for each endpoint
- Getting started guide
- SDK/library examples
More from monkey1sai/openai-cli
multi-tenant-safety-checker
Ensures tenant isolation at query and policy level using Row Level Security, automated testing, and security audits. Prevents data leakage between tenants. Use for "multi-tenancy", "tenant isolation", "RLS", or "data security".
10modal-drawer-system
Implements accessible modals and drawers with focus trap, ESC to close, scroll lock, portal rendering, and ARIA attributes. Includes sample implementations for common use cases like edit forms, confirmations, and detail views. Use when building "modals", "dialogs", "drawers", "sidebars", or "overlays".
10eslint-prettier-config
Configures ESLint and Prettier for consistent code quality with TypeScript, React, and modern best practices. Use when users request "ESLint setup", "Prettier config", "linting configuration", "code formatting", or "lint rules".
9api-security-hardener
Hardens API security with rate limiting, input validation, authentication, and protection against common attacks. Use when users request "API security", "secure API", "rate limiting", "input validation", or "API protection".
9secure-headers-csp-builder
Implements security headers and Content Security Policy with safe rollout strategy (report-only → enforce), testing, and compatibility checks. Use for "security headers", "CSP", "HTTP headers", or "XSS protection".
9security-incident-playbook-generator
Creates response procedures for security incidents with containment steps, communication templates, and evidence collection. Use for "incident response", "security playbook", "breach response", or "IR plan".
9