# Generate API Docs

> Generate comprehensive OpenAPI/Swagger documentation from existing APIs

- Skill: `tools-only/generate-api-docs` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add tools-only/generate-api-docs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/generate-api-docs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/tools-only/generate-api-docs

---

# Generate API Documentation

Automatically generate comprehensive OpenAPI 3.0 specifications with interactive documentation, automated testing, and multi-language client SDKs from your existing API codebase or by analyzing live endpoints.

## When to Use This Command

Use `/generate-api-docs` when you need to:
- Document existing APIs without manual specification writing
- Generate interactive API documentation for developers
- Create Postman/Insomnia collections from your API
- Enable "try it out" functionality for API endpoints
- Generate client SDKs in multiple languages
- Maintain API documentation synchronized with code
- Create API reference documentation for external consumers
- Validate API contracts and schemas
- Enable API mocking for frontend development

DON'T use this when:
- Your API is still in early design phase (use `/api-contract-generator` instead)
- You only need internal code comments (use JSDoc/docstrings)
- Building GraphQL APIs (use `/build-graphql-server` with introspection)
- APIs have no stable contract (too early in development)

## Design Decisions

This command implements **OpenAPI 3.0.3 specification** as the primary approach because:
- Industry standard adopted by major organizations
- Extensive tooling ecosystem (Swagger UI, Redoc, SDKs)
- Supports complex schemas including oneOf, allOf, discriminators
- Native support for webhooks and callbacks
- JSON Schema validation built-in
- Multiple security schemes support

**Alternative considered: API Blueprint**
- Markdown-based format
- Simpler for human writing
- Less tooling support
- Recommended for documentation-first design

**Alternative considered: RAML**
- YAML-based with reusable components
- Good for large enterprise APIs
- Smaller ecosystem
- Recommended when modularity is critical

**Alternative considered: AsyncAPI**
- Specialized for event-driven APIs
- WebSocket and message queue support
- Use alongside OpenAPI for complete coverage

## Prerequisites

Before running this command:
1. Functioning API with consistent patterns
2. Request/response examples available
3. Authentication mechanism implemented
4. Error response format standardized
5. API versioning strategy defined

## Implementation Process

### Step 1: API Analysis and Discovery
Scan codebase and running API to discover all endpoints, methods, and data structures.

### Step 2: Schema Extraction
Extract request/response schemas from code annotations, TypeScript types, or runtime analysis.

### Step 3: OpenAPI Generation
Generate complete OpenAPI 3.0 specification with all paths, schemas, and security definitions.

### Step 4: Documentation Enhancement
Add descriptions, examples, and grouping tags for better organization and understanding.

### Step 5: Interactive Documentation Setup
Deploy Swagger UI and Redoc for interactive API exploration and testing.

## Output Format

The command generates:
- `openapi.yaml` - Main OpenAPI 3.0 specification
- `openapi.json` - JSON format for tooling
- `docs/` - Static HTML documentation
  - `index.html` - Swagger UI interface
  - `redoc.html` - Redoc documentation
- `collections/` - External tool formats
  - `postman_collection.json` - Postman import
  - `insomnia_workspace.json` - Insomnia import
  - `bruno_collection.bru` - Bruno collection
- `examples/` - Request/response examples
- `schemas/` - Extracted JSON schemas
- `README.md` - Getting started guide

## Code Examples

### Example 1: Express.js API with Automatic Documentation Generation

```javascript
// api-documentation-generator.js
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const { z } = require('zod');
const zodToJsonSchema = require('zod-to-json-schema');
const express = require('express');
const fs = require('fs').promises;
const path = require('path');
const yaml = require('js-yaml');

class APIDocumentationGenerator {
  constructor(app, config = {}) {
    this.app = app;
    this.config = {
      title: config.title || 'API Documentation',
      version: config.version || '1.0.0',
      description: config.description || 'API Documentation',
      servers: config.servers || [{ url: 'http://localhost:3000' }],
      contact: config.contact || {},
      license: config.license || { name: 'MIT' },
      security: config.security || [],
      ...config
    };

    this.paths = {};
    this.schemas = {};
    this.examples = {};
    this.tags = [];
  }

  // Analyze Express routes and generate OpenAPI paths
  analyzeRoutes() {
    const routes = [];

    // Extract all routes from Express app
    this.app._router.stack.forEach((middleware) => {
      if (middleware.route) {
        // Regular routes
        routes.push({
          path: middleware.route.path,
          methods: Object.keys(middleware.route.methods)
        });
      } else if (middleware.name === 'router') {
        // Router middleware
        middleware.handle.stack.forEach((handler) => {
          if (handler.route) {
            const basePath = middleware.regexp.source
              .replace('\\/?', '')
              .replace('(?=\\/|$)', '')
              .replace(/\\/g, '/')
              .replace('^', '');

            routes.push({
              path: basePath + handler.route.path,
              methods: Object.keys(handler.route.methods)
            });
          }
        });
      }
    });

    // Convert Express routes to OpenAPI paths
    routes.forEach(route => {
      const openApiPath = this.expressToOpenAPIPath(route.path);

      if (!this.paths[openApiPath]) {
        this.paths[openApiPath] = {};
      }

      route.methods.forEach(method => {
        this.paths[openApiPath][method] = this.generateOperation(
          method,
          route.path,
          openApiPath
        );
      });
    });

    return this.paths;
  }

  // Convert Express path to OpenAPI format
  expressToOpenAPIPath(expressPath) {
    // Convert :param to {param}
    return expressPath.replace(/:([^/]+)/g, '{$1}');
  }

  // Generate operation object for a route
  generateOperation(method, expressPath, openApiPath) {
    const operation = {
      tags: this.inferTags(expressPath),
      summary: this.generateSummary(method, expressPath),
      description: this.generateDescription(method, expressPath),
      operationId: this.generateOperationId(method, expressPath),
      parameters: this.extractParameters(openApiPath),
      responses: this.generateResponses(method, expressPath)
    };

    // Add request body for POST, PUT, PATCH
    if (['post', 'put', 'patch'].includes(method)) {
      operation.requestBody = this.generateRequestBody(method, expressPath);
    }

    // Add security if applicable
    if (this.requiresAuth(expressPath)) {
      operation.security = [{ bearerAuth: [] }];
    }

    return operation;
  }

  // Infer tags from path
  inferTags(path) {
    const segments = path.split('/').filter(s => s && !s.startsWith(':'));
    if (segments.length > 0) {
      const tag = segments[0].charAt(0).toUpperCase() + segments[0].slice(1);

      // Add tag to tags list if not exists
      if (!this.tags.find(t => t.name === tag)) {
        this.tags.push({
          name: tag,
          description: `Operations related to ${tag.toLowerCase()}`
        });
      }

      return [tag];
    }
    return ['General'];
  }

  // Generate operation summary
  generateSummary(method, path) {
    const resource = path.split('/').filter(s => s && !s.startsWith(':')).pop() || 'resource';
    const summaries = {
      get: path.includes(':') ? `Get ${resource} by ID` : `List all ${resource}`,
      post: `Create a new ${resource}`,
      put: `Update ${resource}`,
      patch: `Partially update ${resource}`,
      delete: `Delete ${resource}`,
      head: `Check ${resource} existence`,
      options: `Get ${resource} options`
    };
    return summaries[method] || `${method.toUpperCase()} ${resource}`;
  }

  // Generate detailed description
  generateDescription(method, path) {
    const resource = path.split('/').filter(s => s && !s.startsWith(':')).pop() || 'resource';
    return `Performs a ${method.toUpperCase()} operation on ${resource}. ` +
           `This endpoint ${this.requiresAuth(path) ? 'requires authentication' : 'is publicly accessible'}.`;
  }

  // Generate operation ID
  generateOperationId(method, path) {
    const segments = path.split('/').filter(s => s && !s.startsWith(':'));
    const resource = segments.join('_');
    return `${method}_${resource}`.replace(/[^a-zA-Z0-9_]/g, '_');
  }

  // Extract parameters from path
  extractParameters(path) {
    const parameters = [];

    // Extract path parameters
    const pathParams = path.match(/{([^}]+)}/g);
    if (pathParams) {
      pathParams.forEach(param => {
        const name = param.slice(1, -1);
        parameters.push({
          name,
          in: 'path',
          required: true,
          description: `ID of the ${name}`,
          schema: {
            type: 'string',
            format: name.toLowerCase().includes('id') ? 'uuid' : undefined
          }
        });
      });
    }

    // Add common query parameters for list operations
    if (!path.includes('{')) {
      parameters.push(
        {
          name: 'page',
          in: 'query',
          description: 'Page number for pagination',
          schema: { type: 'integer', default: 1, minimum: 1 }
        },
        {
          name: 'limit',
          in: 'query',
          description: 'Number of items per page',
          schema: { type: 'integer', default: 20, minimum: 1, maximum: 100 }
        },
        {
          name: 'sort',
          in: 'query',
          description: 'Sort field and direction (e.g., "name:asc")',
          schema: { type: 'string' }
        },
        {
          name: 'filter',
          in: 'query',
          description: 'Filter criteria',
          schema: { type: 'string' }
        }
      );
    }

    return parameters;
  }

  // Generate request body schema
  generateRequestBody(method, path) {
    const resource = path.split('/').filter(s => s && !s.startsWith(':')).pop() || 'resource';
    const schemaName = resource.charAt(0).toUpperCase() + resource.slice(1);

    // Generate or retrieve schema
    if (!this.schemas[schemaName]) {
      this.schemas[schemaName] = this.generateResourceSchema(schemaName);
    }

    return {
      required: method === 'post',
      content: {
        'application/json': {
          schema: {
            $ref: `#/components/schemas/${schemaName}`
          },
          examples: this.generateExamples(schemaName)
        }
      }
    };
  }

  // Generate resource schema
  generateResourceSchema(name) {
    // This would ideally extract from your actual models
    // Here's a generic example
    return {
      type: 'object',
      required: ['name'],
      properties: {
        id: {
          type: 'string',
          format: 'uuid',
          readOnly: true,
          description: 'Unique identifier'
        },
        name: {
          type: 'string',
          minLength: 1,
          maxLength: 255,
          description: `Name of the ${name.toLowerCase()}`
        },
        description: {
          type: 'string',
          maxLength: 1000,
          description: 'Detailed description'
        },
        status: {
          type: 'string',
          enum: ['active', 'inactive', 'pending'],
          default: 'active',
          description: 'Current status'
        },
        metadata: {
          type: 'object',
          additionalProperties: true,
          description: 'Additional metadata'
        },
        createdAt: {
          type: 'string',
          format: 'date-time',
          readOnly: true,
          description: 'Creation timestamp'
        },
        updatedAt: {
          type: 'string',
          format: 'date-time',
          readOnly: true,
          description: 'Last update timestamp'
        }
      }
    };
  }

  // Generate response schemas
  generateResponses(method, path) {
    const responses = {
      '200': {
        description: 'Successful operation',
        content: {
          'application/json': {
            schema: this.generateResponseSchema(method, path)
          }
        }
      },
      '400': {
        description: 'Bad request',
        content: {
          'application/json': {
            schema: { $ref: '#/components/schemas/Error' }
          }
        }
      },
      '401': {
        description: 'Unauthorized',
        content: {
          'application/json': {
            schema: { $ref: '#/components/schemas/Error' }
          }
        }
      },
      '404': {
        description: 'Resource not found',
        content: {
          'application/json': {
            schema: { $ref: '#/components/schemas/Error' }
          }
        }
      },
      '500': {
        description: 'Internal server error',
        content: {
          'application/json': {
            schema: { $ref: '#/components/schemas/Error' }
          }
        }
      }
    };

    // Customize based on method
    if (method === 'post') {
      responses['201'] = responses['200'];
      responses['201'].description = 'Resource created successfully';
      delete responses['200'];
    } else if (method === 'delete') {
      responses['204'] = {
        description: 'Resource deleted successfully'
      };
      delete responses['200'];
    }

    return responses;
  }

  // Generate response schema based on operation
  generateResponseSchema(method, path) {
    const resource = path.split('/').filter(s => s && !s.startsWith(':')).pop() || 'resource';
    const schemaName = resource.charAt(0).toUpperCase() + resource.slice(1);

    if (!path.includes(':') && method === 'get') {
      // List operation
      return {
        type: 'object',
        properties: {
          data: {
            type: 'array',
            items: { $ref: `#/components/schemas/${schemaName}` }
          },
          pagination: { $ref: '#/components/schemas/Pagination' },
          meta: { $ref: '#/components/schemas/Meta' }
        }
      };
    } else {
      // Single resource
      return { $ref: `#/components/schemas/${schemaName}` };
    }
  }

  // Generate examples for schemas
  generateExamples(schemaName) {
    return {
      default: {
        summary: 'Standard example',
        value: {
          name: `Example ${schemaName}`,
          description: 'This is an example description',
          status: 'active',
          metadata: {
            category: 'example',
            priority: 'high'
          }
        }
      },
      minimal: {
        summary: 'Minimal required fields',
        value: {
          name: `Minimal ${schemaName}`
        }
      },
      complete: {
        summary: 'All fields populated',
        value: {
          id: '550e8400-e29b-41d4-a716-446655440000',
          name: `Complete ${schemaName}`,
          description: 'This example includes all possible fields',
          status: 'active',
          metadata: {
            category: 'complete',
            priority: 'high',
            tags: ['example', 'complete'],
            customField: 'custom value'
          },
          createdAt: '2024-01-15T10:30:00Z',
          updatedAt: '2024-01-15T14:45:00Z'
        }
      }
    };
  }

  // Check if path requires authentication
  requiresAuth(path) {
    // Implement your auth logic
    const publicPaths = ['/health', '/docs', '/api-docs', '/login', '/register'];
    return !publicPaths.some(p => path.includes(p));
  }

  // Add common schemas
  addCommonSchemas() {
    this.schemas.Error = {
      type: 'object',
      required: ['code', 'message'],
      properties: {
        code: {
          type: 'string',
          description: 'Error code'
        },
        message: {
          type: 'string',
          description: 'Error message'
        },
        details: {
          type: 'object',
          additionalProperties: true,
          description: 'Additional error details'
        },
        timestamp: {
          type: 'string',
          format: 'date-time',
          description: 'Error timestamp'
        }
      }
    };

    this.schemas.Pagination = {
      type: 'object',
      properties: {
        page: { type: 'integer', minimum: 1 },
        limit: { type: 'integer', minimum: 1, maximum: 100 },
        total: { type: 'integer', minimum: 0 },
        pages: { type: 'integer', minimum: 0 }
      }
    };

    this.schemas.Meta = {
      type: 'object',
      properties: {
        version: { type: 'string' },
        timestamp: { type: 'string', format: 'date-time' },
        requestId: { type: 'string', format: 'uuid' }
      }
    };
  }

  // Generate complete OpenAPI specification
  generateOpenAPISpec() {
    // Analyze routes
    this.analyzeRoutes();

    // Add common schemas
    this.addCommonSchemas();

    const spec = {
      openapi: '3.0.3',
      info: {
        title: this.config.title,
        version: this.config.version,
        description: this.config.description,
        contact: this.config.contact,
        license: this.config.license
      },
      servers: this.config.servers,
      tags: this.tags,
      paths: this.paths,
      components: {
        schemas: this.schemas,
        securitySchemes: {
          bearerAuth: {
            type: 'http',
            scheme: 'bearer',
            bearerFormat: 'JWT'
          },
          apiKey: {
            type: 'apiKey',
            name: 'X-API-Key',
            in: 'header'
          },
          oauth2: {
            type: 'oauth2',
            flows: {
              authorizationCode: {
                authorizationUrl: 'https://auth.example.com/oauth/authorize',
                tokenUrl: 'https://auth.example.com/oauth/token',
                refreshUrl: 'https://auth.example.com/oauth/refresh',
                scopes: {
                  read: 'Read access',
                  write: 'Write access',
                  admin: 'Admin access'
                }
              }
            }
          }
        }
      },
      security: this.config.security
    };

    return spec;
  }

  // Export to various formats
  async exportDocumentation(outputDir = './api-docs') {
    const spec = this.generateOpenAPISpec();

    // Create output directory
    await fs.mkdir(outputDir, { recursive: true });
    await fs.mkdir(path.join(outputDir, 'collections'), { recursive: true });

    // Save OpenAPI spec in YAML and JSON
    await fs.writeFile(
      path.join(outputDir, 'openapi.yaml'),
      yaml.dump(spec, { indent: 2 })
    );

    await fs.writeFile(
      path.join(outputDir, 'openapi.json'),
      JSON.stringify(spec, null, 2)
    );

    // Generate Postman collection
    const postmanCollection = this.convertToPostmanCollection(spec);
    await fs.writeFile(
      path.join(outputDir, 'collections', 'postman_collection.json'),
      JSON.stringify(postmanCollection, null, 2)
    );

    // Generate HTML documentation
    await this.generateHTMLDocs(spec, outputDir);

    // Generate README
    await this.generateREADME(spec, outputDir);

    console.log(`API documentation generated in ${outputDir}`);
    return spec;
  }

  // Convert OpenAPI to Postman Collection
  convertToPostmanCollection(openApiSpec) {
    const collection = {
      info: {
        name: openApiSpec.info.title,
        description: openApiSpec.info.description,
        version: openApiSpec.info.version,
        schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
      },
      item: [],
      auth: {
        type: 'bearer',
        bearer: [{
          key: 'token',
          value: '{{access_token}}',
          type: 'string'
        }]
      },
      variable: [
        {
          key: 'baseUrl',
          value: openApiSpec.servers[0].url,
          type: 'string'
        },
        {
          key: 'access_token',
          value: '',
          type: 'string'
        }
      ]
    };

    // Group by tags
    const folders = {};

    Object.entries(openApiSpec.paths).forEach(([path, methods]) => {
      Object.entries(methods).forEach(([method, operation]) => {
        const tag = operation.tags?.[0] || 'General';

        if (!folders[tag]) {
          folders[tag] = {
            name: tag,
            item: []
          };
        }

        const request = {
          name: operation.summary,
          request: {
            method: method.toUpperCase(),
            header: [],
            url: {
              raw: `{{baseUrl}}${path}`,
              host: ['{{baseUrl}}'],
              path: path.split('/').filter(p => p)
            },
            description: operation.description
          }
        };

        // Add path parameters
        if (operation.parameters) {
          const pathParams = operation.parameters.filter(p => p.in === 'path');
          const queryParams = operation.parameters.filter(p => p.in === 'query');

          if (pathParams.length > 0) {
            request.request.url.variable = pathParams.map(p => ({
              key: p.name,
              value: '',
              description: p.description
            }));
          }

          if (queryParams.length > 0) {
            request.request.url.query = queryParams.map(p => ({
              key: p.name,
              value: '',
              description: p.description,
              disabled: !p.required
            }));
          }
        }

        // Add request body
        if (operation.requestBody) {
          const content = operation.requestBody.content['application/json'];
          if (content) {
            request.request.header.push({
              key: 'Content-Type',
              value: 'application/json'
            });

            request.request.body = {
              mode: 'raw',
              raw: JSON.stringify(
                content.examples?.default?.value || {},
                null,
                2
              )
            };
          }
        }

        // Add auth if required
        if (operation.security) {
          request.request.auth = {
            type: 'bearer',
            bearer: [{
              key: 'token',
              value: '{{access_token}}'
            }]
          };
        }

        folders[tag].item.push(request);
      });
    });

    collection.item = Object.values(folders);
    return collection;
  }

  // Generate HTML documentation
  async generateHTMLDocs(spec, outputDir) {
    // Swagger UI HTML
    const swaggerHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>${spec.info.title} - Swagger UI</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css">
    <style>
      body { margin: 0; padding: 0; }
      .swagger-ui .topbar { display: none; }
    </style>
</head>
<body>
    <div id="swagger-ui"></div>
    <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js"></script>
    <script>
      window.onload = () => {
        window.ui = SwaggerUIBundle({
          url: './openapi.json',
          dom_id: '#swagger-ui',
          presets: [
            SwaggerUIBundle.presets.apis,
            SwaggerUIStandalonePreset
          ],
          layout: "BaseLayout",
          deepLinking: true,
          showExtensions: true,
          showCommonExtensions: true,
          tryItOutEnabled: true
        });
      };
    </script>
</body>
</html>`;

    // Redoc HTML
    const redocHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>${spec.info.title} - ReDoc</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body { margin: 0; padding: 0; }
    </style>
</head>
<body>
    <redoc spec-url='./openapi.json'></redoc>
    <script src="https://cdn.jsdelivr.net/npm/redoc@2.0.0/bundles/redoc.standalone.js"></script>
</body>
</html>`;

    await fs.writeFile(path.join(outputDir, 'index.html'), swaggerHtml);
    await fs.writeFile(path.join(outputDir, 'redoc.html'), redocHtml);
  }

  // Generate README documentation
  async generateREADME(spec, outputDir) {
    const readme = `# ${spec.info.title}

${spec.info.description}

**Version:** ${spec.info.version}

## Base URL

\`\`\`
${spec.servers.map(s => s.url).join('\n')}
\`\`\`

## Authentication

This API uses the following authentication methods:
${spec.components.securitySchemes ? Object.entries(spec.components.securitySchemes).map(([name, scheme]) =>
  `- **${name}**: ${scheme.type} ${scheme.scheme || ''}`
).join('\n') : '- No authentication required'}

## Available Endpoints

${Object.entries(spec.paths).map(([path, methods]) =>
  Object.entries(methods).map(([method, op]) =>
    `- \`${method.toUpperCase()} ${path}\` - ${op.summary}`
  ).join('\n')
).join('\n')}

## Quick Start

### Installation

\`\`\`bash
# Using npm
npm install axios

# Using curl
curl -X GET "${spec.servers[0].url}/endpoint"
\`\`\`

### Example Request

\`\`\`javascript
const axios = require('axios');

const config = {
  method: 'get',
  url: '${spec.servers[0].url}${Object.keys(spec.paths)[0]}',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
  }
};

axios(config)
  .then(response => {
    console.log(JSON.stringify(response.data));
  })
  .catch(error => {
    console.error(error);
  });
\`\`\`

## Documentation

- [Swagger UI](./index.html) - Interactive API documentation
- [ReDoc](./redoc.html) - Alternative documentation format
- [OpenAPI Spec](./openapi.json) - Raw OpenAPI specification
- [Postman Collection](./collections/postman_collection.json) - Import to Postman

## SDKs

Generate client SDKs using:

\`\`\`bash
# JavaScript/TypeScript
npx @openapitools/openapi-generator-cli generate -i openapi.yaml -g typescript-axios -o ./sdk/typescript

# Python
openapi-generator-cli generate -i openapi.yaml -g python -o ./sdk/python

# Go
openapi-generator-cli generate -i openapi.yaml -g go -o ./sdk/go
\`\`\`

## Support

${spec.info.contact?.email ? `For support, contact ${spec.info.contact.email}` : 'For support, please refer to the documentation.'}

## License

${spec.info.license?.name || 'See LICENSE file'}
`;

    await fs.writeFile(path.join(outputDir, 'README.md'), readme);
  }

  // Setup interactive documentation routes
  setupDocumentationRoutes(basePath = '/api-docs') {
    // Serve OpenAPI spec
    this.app.get(`${basePath}/openapi.json`, (req, res) => {
      res.json(this.generateOpenAPISpec());
    });

    // Serve Swagger UI
    this.app.use(
      `${basePath}`,
      swaggerUi.serve,
      swaggerUi.setup(this.generateOpenAPISpec(), {
        customCss: '.swagger-ui .topbar { display: none }',
        customSiteTitle: this.config.title
      })
    );

    console.log(`API documentation available at ${basePath}`);
  }
}

// Usage example
const app = express();

const docGenerator = new APIDocumentationGenerator(app, {
  title: 'E-commerce API',
  version: '2.0.0',
  description: 'Complete e-commerce platform API with user management, products, and orders',
  servers: [
    { url: 'https://api.example.com/v2', description: 'Production' },
    { url: 'https://staging-api.example.com/v2', description: 'Staging' },
    { url: 'http://localhost:3000', description: 'Development' }
  ],
  contact: {
    name: 'API Support',
    email: 'api@example.com',
    url: 'https://support.example.com'
  }
});

// Generate and export documentation
docGenerator.exportDocumentation('./api-documentation');

// Setup interactive docs
docGenerator.setupDocumentationRoutes('/docs');

module.exports = APIDocumentationGenerator;
```

### Example 2: Python FastAPI with Automatic OpenAPI Enhancement

```python
# api_doc_enhancer.py
from fastapi import FastAPI, APIRouter, Depends, HTTPException
from fastapi.openapi.utils import get_openapi
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
from pydantic import BaseModel, Field
from typing import List, Optional, Dict, Any
import json
import yaml
from pathlib import Path
import httpx
from datetime import datetime

class OpenAPIEnhancer:
    """Enhance FastAPI's auto-generated OpenAPI with additional features"""

    def __init__(self, app: FastAPI):
        self.app = app
        self.examples = {}
        self.additional_schemas = {}
        self.external_docs = {}

    def enhance_openapi(self):
        """Enhance the OpenAPI spec with additional information"""
        if self.app.openapi_schema:
            return self.app.openapi_schema

        openapi_schema = get_openapi(
            title=self.app.title,
            version=self.app.version,
            description=self.app.description,
            routes=self.app.routes,
        )

        # Add custom enhancements
        self._add_api_versioning(openapi_schema)
        self._add_rate_limiting_info(openapi_schema)
        self._add_webhook_definitions(openapi_schema)
        self._add_code_samples(openapi_schema)
        self._add_security_schemes(openapi_schema)
        self._add_server_variables(openapi_schema)
        self._enhance_schemas(openapi_schema)
        self._add_tags_metadata(openapi_schema)

        self.app.openapi_schema = openapi_schema
        return self.app.openapi_schema

    def _add_api_versioning(self, spec: Dict[str, Any]):
        """Add API versioning information"""
        spec["info"]["x-api-versioning"] = {
            "strategy": "uri",
            "current": "v2",
            "supported": ["v1", "v2"],
            "deprecated": ["v0"],
            "sunset": {
                "v0": "2024-01-01",
                "v1": "2025-01-01"
            }
        }

    def _add_rate_limiting_info(self, spec: Dict[str, Any]):
        """Add rate limiting documentation"""
        spec["info"]["x-rate-limiting"] = {
            "default": {
                "requests": 1000,
                "window": "1h"
            },
            "authenticated": {
                "requests": 5000,
                "window": "1h"
            },
            "endpoints": {
                "/api/search": {
                    "requests": 100,
                    "window": "1m"
                }
            },
            "headers": {
                "limit": "X-RateLimit-Limit",
                "remaining": "X-RateLimit-Remaining",
                "reset": "X-RateLimit-Reset"
            }
        }

    def _add_webhook_definitions(self, spec: Dict[str, Any]):
        """Add webhook definitions to OpenAPI spec"""
        spec["webhooks"] = {
            "orderCreated": {
                "post": {
                    "requestBody": {
                        "description": "Order creation notification",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OrderWebhook"
                                }
                            }
                        }
                    },
                    "responses": {
                        "200": {
                            "description": "Webhook processed successfully"
                        }
                    }
                }
            },
            "paymentProcessed": {
                "post": {
                    "requestBody": {
                        "description": "Payment processing notification",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaymentWebhook"
                                }
                            }
                        }
                    },
                    "responses": {
                        "200": {
                            "description": "Webhook acknowledged"
                        }
                    }
                }
            }
        }

        # Add webhook schemas
        if "components" not in spec:
            spec["components"] = {}
        if "schemas" not in spec["components"]:
            spec["components"]["schemas"] = {}

        spec["components"]["schemas"]["OrderWebhook"] = {
            "type": "object",
            "required": ["event", "data", "timestamp"],
            "properties": {
                "event": {
                    "type": "string",
                    "enum": ["order.created", "order.updated", "order.cancelled"]
                },
                "data": {
                    "type": "object",
                    "properties": {
                        "orderId": {"type": "string", "format": "uuid"},
                        "customerId": {"type": "string", "format": "uuid"},
                        "amount": {"type": "number", "format": "float"},
                        "status": {"type": "string"}
                    }
                },
                "timestamp": {
                    "type": "string",
                    "format": "date-time"
                }
            }
        }

    def _add_code_samples(self, spec: Dict[str, Any]):
        """Add code samples to each endpoint"""
        for path, methods in spec.get("paths", {}).items():
            for method, operation in methods.items():
                if method in ["get", "post", "put", "delete", "patch"]:
                    operation["x-code-samples"] = self._generate_code_samples(
                        method, path, operation
                    )

    def _generate_code_samples(self, method: str, path: str, operation: Dict) -> List[Dict]:
        """Generate code samples for multiple languages"""
        samples = []

        # cURL example
        curl_sample = f"curl -X {method.upper()} '{self.app.servers[0]['url'] if hasattr(self.app, 'servers') else 'https://api.example.com'}{path}'"
        if method in ["post", "put", "patch"]:
            curl_sample += """ \\
  -H 'Content-Type: application/json' \\
  -H 'Authorization: Bearer YOUR_TOKEN' \\
  -d '{
    "name": "example",
    "value": 123
  }'"""
        else:
            curl_sample += " \\\n  -H 'Authorization: Bearer YOUR_TOKEN'"

        samples.append({
            "lang": "Shell",
            "source": curl_sample,
            "label": "cURL"
        })

        # Python example
        python_sample = f"""import requests

url = "https://api.example.com{path}"
headers = {{
    "Authorization": "Bearer YOUR_TOKEN",
    "Content-Type": "application/json"
}}"""

        if method in ["post", "put", "patch"]:
            python_sample += """
data = {
    "name": "example",
    "value": 123
}
response = requests.""" + method + """(url, json=data, headers=headers)"""
        else:
            python_sample += f"""
response = requests.{method}(url, headers=headers)"""

        python_sample += """
print(response.json())"""

        samples.append({
            "lang": "Python",
            "source": python_sample,
            "label": "Python (requests)"
        })

        # JavaScript example
        js_sample = f"""const axios = require('axios');

const config = {{
  method: '{method}',
  url: 'https://api.example.com{path}',
  headers: {{
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
  }}"""

        if method in ["post", "put", "patch"]:
            js_sample += """,
  data: {
    name: 'example',
    value: 123
  }"""

        js_sample += """
};

axios(config)
  .then(response => {
    console.log(JSON.stringify(response.data));
  })
  .catch(error => {
    console.error(error);
  });"""

        samples.append({
            "lang": "JavaScript",
            "source": js_sample,
            "label": "Node.js (axios)"
        })

        # Go example
        go_sample = f"""package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {{
    url := "https://api.example.com{path}"

"""

        if method in ["post", "put", "patch"]:
            go_sample += """    payload := map[string]interface{}{
        "name": "example",
        "value": 123,
    }

    jsonData, _ := json.Marshal(payload)
    req, _ := http.NewRequest(""" + f'"{method.upper()}", url, bytes.NewBuffer(jsonData))'
        else:
            go_sample += f"""    req, _ := http.NewRequest("{method.upper()}", url, nil)"""

        go_sample += """
    req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}"""

        samples.append({
            "lang": "Go",
            "source": go_sample,
            "label": "Go (net/http)"
        })

        return samples

    def _add_security_schemes(self, spec: Dict[str, Any]):
        """Add comprehensive security schemes"""
        if "components" not in spec:
            spec["components"] = {}

        spec["components"]["securitySchemes"] = {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT",
                "description": "JWT token authentication"
            },
            "apiKey": {
                "type": "apiKey",
                "name": "X-API-Key",
                "in": "header",
                "description": "API key authentication"
            },
            "oauth2": {
                "type": "oauth2",
                "flows": {
                    "authorizationCode": {
                        "authorizationUrl": "https://auth.example.com/oauth/authorize",
                        "tokenUrl": "https://auth.example.com/oauth/token",
                        "refreshUrl": "https://auth.example.com/oauth/refresh",
                        "scopes": {
                            "read": "Read access to protected resources",
                            "write": "Write access to protected resources",
                            "admin": "Admin access to all resources"
                        }
                    },
                    "clientCredentials": {
                        "tokenUrl": "https://auth.example.com/oauth/token",
                        "scopes": {
                            "api": "API access"
                        }
                    }
                }
            },
            "cookieAuth": {
                "type": "apiKey",
                "in": "cookie",
                "name": "session_id",
                "description": "Session cookie authentication"
            }
        }

    def _add_server_variables(self, spec: Dict[str, Any]):
        """Add server variables for environment switching"""
        spec["servers"] = [
            {
                "url": "https://{environment}.api.example.com/{version}",
                "description": "API Server",
                "variables": {
                    "environment": {
                        "enum": ["production", "staging", "development"],
                        "default": "production",
                        "description": "Server environment"
                    },
                    "version": {
                        "enum": ["v1", "v2", "v3"],
                        "default": "v2",
                        "description": "API version"
                    }
                }
            },
            {
                "url": "http://localhost:{port}",
                "description": "Local development server",
                "variables": {
                    "port": {
                        "enum": ["3000", "8000", "8080"],
                        "default": "8000",
                        "description": "Server port"
                    }
                }
            }
        ]

    

…(truncated)
