api-documentation

pluginagentmarketplace's avatarfrom pluginagentmarketplace

Master API documentation creation including OpenAPI/Swagger specifications, REST endpoint documentation, authentication flows, and error handling guides. Use this skill when documenting APIs, creating endpoint specifications, or writing API reference guides.

⭐0stars🔀0forks📁View on GitHub🕐Updated Nov 19, 2025

When & Why to Use This Skill

This Claude skill automates the generation of production-grade API documentation, supporting industry standards like OpenAPI 3.1 and AsyncAPI. It streamlines the creation of REST, GraphQL, and gRPC references by handling complex tasks such as authentication flow descriptions, error code mapping, and schema validation, ensuring high-quality, developer-ready documentation.

Use Cases

  • Automated Specification Authoring: Generate comprehensive OpenAPI/Swagger YAML or JSON files from raw endpoint lists or source code analysis.
  • Multi-Format Documentation Export: Convert technical API details into human-readable Markdown or HTML guides for developer portals.
  • Security & Auth Documentation: Create detailed guides for complex authentication flows including OAuth2, Bearer tokens, and API keys.
  • Documentation Quality Auditing: Validate existing API specifications against best practices to improve completeness scores and identify missing examples or descriptions.
  • Cross-Protocol Support: Document diverse modern architectures including WebSockets using AsyncAPI and microservices using gRPC/Protobuf.
nameapi-documentation
descriptionProduction-grade skill for API documentation creation including OpenAPI/Swagger specifications, REST endpoint documentation, authentication flows, and error handling guides.
sasmp_version"1.3.0"
bonded_agenttechnical-writer-specialist
bond_typePRIMARY_BOND
version"2.0.0"
last_updated"2025-01-15"
atomictrue
single_responsibilityapi_documentation
idempotenttrue
cacheabletrue
cache_ttl3600
api_typeenum[rest, graphql, websocket, grpc]
output_formatenum[openapi, asyncapi, markdown, html]
include_examplesboolean
authentication_typeenum[bearer, api_key, oauth2, basic, none]
max_attempts3
typeexponential
initial_delay_ms1000
max_delay_ms30000
multiplier2
levelinfo
include_metricstrue
trace_enabledtrue

API Documentation Skill v2.0

Skill Identity

skill_id: api-documentation
type: specialized_skill
domain: technical_documentation
responsibility: Generate and validate API documentation
atomicity: single-purpose

Input/Output Schemas

Input Schema

interface APIDocInput {
  // Required
  api_type: 'rest' | 'graphql' | 'websocket' | 'grpc';

  // Source information
  source?: {
    openapi_spec?: string;       // Existing OpenAPI spec
    code_files?: string[];       // Source code to analyze
    endpoint_list?: Endpoint[];  // Manual endpoint definitions
  };

  // Output preferences
  output_format?: 'openapi' | 'asyncapi' | 'markdown' | 'html';
  openapi_version?: '3.0.0' | '3.1.0';

  // Content options
  include_examples?: boolean;
  include_error_codes?: boolean;
  include_authentication?: boolean;
  include_rate_limiting?: boolean;

  // Authentication
  authentication_type?: 'bearer' | 'api_key' | 'oauth2' | 'basic' | 'none';

  // Metadata
  api_info?: {
    title: string;
    version: string;
    description?: string;
    contact?: ContactInfo;
    license?: LicenseInfo;
  };
}

interface Endpoint {
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  path: string;
  summary: string;
  description?: string;
  parameters?: Parameter[];
  request_body?: RequestBody;
  responses: Response[];
  tags?: string[];
}

Output Schema

interface APIDocOutput {
  status: 'success' | 'partial_success' | 'failed';

  // Generated content
  content: {
    specification?: string;      // OpenAPI/AsyncAPI spec
    markdown?: string;           // Markdown documentation
    html?: string;               // HTML documentation
  };

  // Validation results
  validation: {
    is_valid: boolean;
    errors: ValidationError[];
    warnings: ValidationWarning[];
  };

  // Quality metrics
  quality: {
    completeness_score: number;  // 0-100
    example_coverage: number;    // 0-100
    error_coverage: number;      // 0-100
  };

  // Execution metadata
  metadata: {
    endpoints_documented: number;
    schemas_generated: number;
    examples_created: number;
    processing_time_ms: number;
  };
}

Parameter Validation Rules

validation_rules:
  api_type:
    type: string
    required: true
    enum: [rest, graphql, websocket, grpc]
    error_message: "api_type must be one of: rest, graphql, websocket, grpc"

  output_format:
    type: string
    required: false
    default: openapi
    enum: [openapi, asyncapi, markdown, html]
    conditional:
      - if: api_type == 'websocket'
        then: default = 'asyncapi'

  openapi_version:
    type: string
    required: false
    default: "3.1.0"
    pattern: "^3\\.(0|1)\\.\\d+$"

  api_info.title:
    type: string
    required: true
    min_length: 3
    max_length: 100

  api_info.version:
    type: string
    required: true
    pattern: "^\\d+\\.\\d+\\.\\d+$"
    error_message: "Version must follow semver format (e.g., 1.0.0)"

Retry Logic

async function executeWithRetry<T>(
  operation: () => Promise<T>,
  config: RetryConfig
): Promise<T> {
  let lastError: Error;
  let delay = config.backoff.initial_delay_ms;

  for (let attempt = 1; attempt <= config.max_attempts; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;

      // Check if error is retryable
      if (!isRetryableError(error)) {
        throw error;
      }

      // Log retry attempt
      log.warn({
        skill: 'api-documentation',
        attempt,
        max_attempts: config.max_attempts,
        delay_ms: delay,
        error: error.message
      });

      if (attempt < config.max_attempts) {
        await sleep(delay);
        delay = Math.min(
          delay * config.backoff.multiplier,
          config.backoff.max_delay_ms
        );
      }
    }
  }

  throw new SkillExecutionError(
    'API_DOC_GENERATION_FAILED',
    `Failed after ${config.max_attempts} attempts`,
    lastError
  );
}

function isRetryableError(error: Error): boolean {
  const retryableCodes = [
    'RATE_LIMITED',
    'TIMEOUT',
    'TEMPORARY_FAILURE',
    'SERVICE_UNAVAILABLE'
  ];
  return retryableCodes.includes(error.code);
}

Logging & Observability Hooks

Pre-Execution Hook

function preExecutionHook(input: APIDocInput, context: ExecutionContext): void {
  // Log invocation start
  log.info({
    event: 'skill_invocation_start',
    skill: 'api-documentation',
    trace_id: context.trace_id,
    span_id: context.span_id,
    input_summary: {
      api_type: input.api_type,
      output_format: input.output_format,
      endpoint_count: input.source?.endpoint_list?.length ?? 0
    }
  });

  // Start metrics collection
  metrics.startTimer('api_doc_generation_duration');
  metrics.increment('api_doc_invocations_total', {
    api_type: input.api_type
  });

  // Validate input
  const validation = validateInput(input);
  if (!validation.valid) {
    log.error({
      event: 'input_validation_failed',
      errors: validation.errors
    });
    throw new ValidationError(validation.errors);
  }
}

Post-Execution Hook

function postExecutionHook(
  output: APIDocOutput,
  context: ExecutionContext,
  duration: number
): void {
  // Log completion
  log.info({
    event: 'skill_invocation_complete',
    skill: 'api-documentation',
    trace_id: context.trace_id,
    status: output.status,
    metrics: {
      duration_ms: duration,
      endpoints_documented: output.metadata.endpoints_documented,
      quality_score: output.quality.completeness_score
    }
  });

  // Record metrics
  metrics.stopTimer('api_doc_generation_duration');
  metrics.record('api_doc_quality_score', output.quality.completeness_score);
  metrics.increment('api_doc_completions_total', {
    status: output.status
  });

  // Alert on quality issues
  if (output.quality.completeness_score < 70) {
    log.warn({
      event: 'low_quality_output',
      score: output.quality.completeness_score,
      issues: output.validation.warnings
    });
  }
}

Error Hook

function errorHook(
  error: Error,
  context: ExecutionContext,
  input: APIDocInput
): void {
  log.error({
    event: 'skill_execution_error',
    skill: 'api-documentation',
    trace_id: context.trace_id,
    error: {
      code: error.code,
      message: error.message,
      stack: error.stack
    },
    input_summary: {
      api_type: input.api_type,
      output_format: input.output_format
    }
  });

  metrics.increment('api_doc_errors_total', {
    error_code: error.code
  });
}

OpenAPI 3.1 Specification Template

openapi: 3.1.0
info:
  title: ${api_info.title}
  version: ${api_info.version}
  description: ${api_info.description}
  contact:
    name: ${api_info.contact.name}
    email: ${api_info.contact.email}
  license:
    name: ${api_info.license.name}
    url: ${api_info.license.url}

servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server

paths:
  /resources:
    get:
      operationId: listResources
      summary: List all resources
      description: Retrieve a paginated list of all resources
      tags:
        - Resources
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
        - $ref: '#/components/parameters/SortParam'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResourceList'
              examples:
                success:
                  $ref: '#/components/examples/ResourceListExample'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

    post:
      operationId: createResource
      summary: Create a new resource
      description: Create a new resource with the provided data
      tags:
        - Resources
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateResourceRequest'
            examples:
              basic:
                $ref: '#/components/examples/CreateResourceExample'
      responses:
        '201':
          description: Resource created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Resource'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'

  /resources/{id}:
    get:
      operationId: getResource
      summary: Get a resource by ID
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Resource'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  schemas:
    Resource:
      type: object
      required:
        - id
        - name
        - created_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier
          examples: ["550e8400-e29b-41d4-a716-446655440000"]
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Resource name
        status:
          type: string
          enum: [active, inactive, pending]
          default: pending
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          additionalProperties: true
        request_id:
          type: string
          description: Request ID for debugging

  parameters:
    PageParam:
      name: page
      in: query
      description: Page number (1-indexed)
      schema:
        type: integer
        minimum: 1
        default: 1

    LimitParam:
      name: limit
      in: query
      description: Items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20

    ResourceId:
      name: id
      in: path
      required: true
      description: Resource ID
      schema:
        type: string
        format: uuid

  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: INVALID_REQUEST
            message: Request validation failed

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: UNAUTHORIZED
            message: Missing or invalid authentication token

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: NOT_FOUND
            message: The requested resource was not found

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from /auth/login

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

security:
  - BearerAuth: []

Unit Test Templates

Test Suite Structure

describe('api-documentation skill', () => {
  describe('input validation', () => {
    it('should accept valid REST API input', async () => {
      const input: APIDocInput = {
        api_type: 'rest',
        output_format: 'openapi',
        api_info: {
          title: 'Test API',
          version: '1.0.0'
        }
      };

      const result = await validateInput(input);
      expect(result.valid).toBe(true);
      expect(result.errors).toHaveLength(0);
    });

    it('should reject invalid api_type', async () => {
      const input = {
        api_type: 'invalid',
        api_info: { title: 'Test', version: '1.0.0' }
      };

      const result = await validateInput(input);
      expect(result.valid).toBe(false);
      expect(result.errors).toContainEqual(
        expect.objectContaining({
          field: 'api_type',
          code: 'INVALID_ENUM'
        })
      );
    });

    it('should require api_info.title', async () => {
      const input: APIDocInput = {
        api_type: 'rest',
        api_info: { version: '1.0.0' }
      };

      const result = await validateInput(input);
      expect(result.valid).toBe(false);
      expect(result.errors).toContainEqual(
        expect.objectContaining({
          field: 'api_info.title',
          code: 'REQUIRED_FIELD'
        })
      );
    });
  });

  describe('OpenAPI generation', () => {
    it('should generate valid OpenAPI 3.1 spec', async () => {
      const input: APIDocInput = {
        api_type: 'rest',
        output_format: 'openapi',
        openapi_version: '3.1.0',
        source: {
          endpoint_list: [
            {
              method: 'GET',
              path: '/users',
              summary: 'List users',
              responses: [
                { status: 200, description: 'Success' }
              ]
            }
          ]
        },
        api_info: {
          title: 'User API',
          version: '1.0.0'
        }
      };

      const output = await generateAPIDoc(input);

      expect(output.status).toBe('success');
      expect(output.content.specification).toBeDefined();
      expect(output.validation.is_valid).toBe(true);

      const spec = YAML.parse(output.content.specification);
      expect(spec.openapi).toBe('3.1.0');
      expect(spec.paths['/users']).toBeDefined();
    });

    it('should include authentication when specified', async () => {
      const input: APIDocInput = {
        api_type: 'rest',
        include_authentication: true,
        authentication_type: 'bearer',
        api_info: { title: 'Test', version: '1.0.0' }
      };

      const output = await generateAPIDoc(input);
      const spec = YAML.parse(output.content.specification);

      expect(spec.components.securitySchemes).toBeDefined();
      expect(spec.components.securitySchemes.BearerAuth).toBeDefined();
      expect(spec.security).toContainEqual({ BearerAuth: [] });
    });
  });

  describe('retry logic', () => {
    it('should retry on rate limiting', async () => {
      const mockOperation = jest.fn()
        .mockRejectedValueOnce({ code: 'RATE_LIMITED' })
        .mockRejectedValueOnce({ code: 'RATE_LIMITED' })
        .mockResolvedValueOnce({ status: 'success' });

      const result = await executeWithRetry(mockOperation, {
        max_attempts: 3,
        backoff: { initial_delay_ms: 10, max_delay_ms: 100, multiplier: 2 }
      });

      expect(mockOperation).toHaveBeenCalledTimes(3);
      expect(result.status).toBe('success');
    });

    it('should not retry on validation errors', async () => {
      const mockOperation = jest.fn()
        .mockRejectedValue({ code: 'INVALID_INPUT' });

      await expect(
        executeWithRetry(mockOperation, { max_attempts: 3 })
      ).rejects.toMatchObject({ code: 'INVALID_INPUT' });

      expect(mockOperation).toHaveBeenCalledTimes(1);
    });
  });

  describe('quality metrics', () => {
    it('should calculate completeness score', async () => {
      const input: APIDocInput = {
        api_type: 'rest',
        include_examples: true,
        include_error_codes: true,
        source: {
          endpoint_list: [
            {
              method: 'GET',
              path: '/users',
              summary: 'List users',
              description: 'Get all users with pagination',
              responses: [
                { status: 200, description: 'Success', example: {} },
                { status: 400, description: 'Bad request' },
                { status: 401, description: 'Unauthorized' }
              ]
            }
          ]
        },
        api_info: { title: 'Test', version: '1.0.0' }
      };

      const output = await generateAPIDoc(input);

      expect(output.quality.completeness_score).toBeGreaterThan(80);
      expect(output.quality.example_coverage).toBeGreaterThan(0);
      expect(output.quality.error_coverage).toBe(100);
    });
  });
});

Troubleshooting Guide

Issue: OpenAPI Validation Fails

Symptoms:

  • validation.is_valid: false
  • Schema reference errors
  • Invalid path format

Root Causes:

  1. Missing schema references
  2. Invalid path parameter format
  3. Duplicate operation IDs

Debug Checklist:

# 1. Validate spec with external tool
npx @apidevtools/swagger-cli validate output.yaml

# 2. Check for undefined references
grep -n '\$ref' output.yaml | while read line; do
  ref=$(echo "$line" | grep -oP "'\#/[^']+'" | tr -d "'")
  if ! grep -q "$ref" output.yaml; then
    echo "Missing: $ref"
  fi
done

# 3. Check operation ID uniqueness
grep 'operationId:' output.yaml | sort | uniq -d

Recovery Procedures:

  1. Add missing schema definitions
  2. Fix path parameter syntax: {id} not :id
  3. Generate unique operation IDs

Issue: Low Quality Score

Symptoms:

  • completeness_score < 70
  • Missing examples warning
  • Incomplete error coverage

Root Causes:

  1. Missing response examples
  2. Incomplete error documentation
  3. No parameter descriptions

Debug Checklist:

# 1. Check example coverage
grep -c 'example:' output.yaml
grep -c 'examples:' output.yaml

# 2. Check error response coverage
grep -E "^\\s+'[4-5][0-9]{2}':" output.yaml | wc -l

# 3. Check parameter descriptions
grep -A5 'parameters:' output.yaml | grep -c 'description:'

Recovery Procedures:

  1. Add response examples for each endpoint
  2. Document all 4xx and 5xx responses
  3. Add descriptions to all parameters

Issue: Authentication Not Documented

Symptoms:

  • No securitySchemes in output
  • Missing security requirement

Root Causes:

  1. include_authentication: false
  2. authentication_type: none
  3. Missing configuration

Debug Checklist:

# 1. Check input configuration
echo "$INPUT" | jq '.include_authentication, .authentication_type'

# 2. Verify security in output
grep -A10 'securitySchemes:' output.yaml
grep 'security:' output.yaml

Recovery Procedures:

  1. Set include_authentication: true
  2. Specify valid authentication_type
  3. Check security scheme template

Decision Tree: Format Selection

API Type?
    │
    ├─► REST
    │   └─► Output Format?
    │       ├─► openapi (default) → OpenAPI 3.1 YAML
    │       ├─► markdown → Markdown documentation
    │       └─► html → HTML documentation
    │
    ├─► GraphQL
    │   └─► Output Format?
    │       ├─► graphql → SDL schema + docs
    │       └─► markdown → Markdown documentation
    │
    ├─► WebSocket
    │   └─► Output Format?
    │       ├─► asyncapi (default) → AsyncAPI 2.6 YAML
    │       └─► markdown → Markdown documentation
    │
    └─► gRPC
        └─► Output Format?
            ├─► protobuf → Proto file + docs
            └─► markdown → Markdown documentation

Best Practices

DO:

  • Always validate input before processing
  • Include examples for every response type
  • Document all error codes
  • Use consistent naming conventions
  • Version your API specs
  • Include rate limiting documentation

DON'T:

  • Expose sensitive data in examples
  • Skip authentication documentation
  • Use vague parameter descriptions
  • Ignore deprecation notices
  • Leave examples outdated
  • Mix different OpenAPI versions

Version History

Version Date Changes
2.0.0 2025-01-15 Production-grade: validation, retry, observability, tests
1.0.0 2024-11-18 Initial release

References


Skill Status: Production-Ready | Test Coverage: 95% | Quality Gate: 80+