Files
flyer-crawler.projectium.com/docs/adr/0018-api-documentation-strategy.md
Torben Sorensen 4e22213cd1
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 15m54s
all the new shiny things
2026-01-11 02:04:52 -08:00

8.3 KiB

ADR-018: API Documentation Strategy

Date: 2025-12-12

Status: Accepted

Implemented: 2026-01-11

Context

As the API grows, it becomes increasingly difficult for frontend developers and other consumers to understand its endpoints, request formats, and response structures. There is no single source of truth for API documentation.

Key requirements:

  1. Developer Experience: Developers need interactive documentation to explore and test API endpoints.
  2. Code-Documentation Sync: Documentation should stay in sync with the actual code to prevent drift.
  3. Low Maintenance Overhead: The documentation approach should be "fast and lite" - minimal additional work for developers.
  4. Security: Documentation should not expose sensitive information in production environments.

Decision

We will adopt OpenAPI 3.0 (Swagger) for API documentation using the following approach:

  1. JSDoc Annotations: Use swagger-jsdoc to generate OpenAPI specs from JSDoc comments in route files.
  2. Swagger UI: Use swagger-ui-express to serve interactive documentation at /docs/api-docs.
  3. Environment Restriction: Only expose the Swagger UI in development and test environments, not production.
  4. Incremental Adoption: Start with key public routes and progressively add annotations to all endpoints.

Tooling Selection

Tool Purpose
swagger-jsdoc Generates OpenAPI 3.0 spec from JSDoc comments
swagger-ui-express Serves interactive Swagger UI

Why JSDoc over separate schema files?

  • Documentation lives with the code, reducing drift
  • No separate files to maintain
  • Developers see documentation when editing routes
  • Lower learning curve for the team

Implementation Details

OpenAPI Configuration

Located in src/config/swagger.ts:

import swaggerJsdoc from 'swagger-jsdoc';

const options: swaggerJsdoc.Options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'Flyer Crawler API',
      version: '1.0.0',
      description: 'API for the Flyer Crawler application',
      contact: {
        name: 'API Support',
      },
    },
    servers: [
      {
        url: '/api',
        description: 'API server',
      },
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
        },
      },
    },
  },
  apis: ['./src/routes/*.ts'],
};

export const swaggerSpec = swaggerJsdoc(options);

JSDoc Annotation Pattern

Each route handler should include OpenAPI annotations using the @openapi tag:

/**
 * @openapi
 * /health/ping:
 *   get:
 *     summary: Simple ping endpoint
 *     description: Returns a pong response to verify server is responsive
 *     tags:
 *       - Health
 *     responses:
 *       200:
 *         description: Server is responsive
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                   example: true
 *                 data:
 *                   type: object
 *                   properties:
 *                     message:
 *                       type: string
 *                       example: pong
 */
router.get('/ping', validateRequest(emptySchema), (_req: Request, res: Response) => {
  return sendSuccess(res, { message: 'pong' });
});

Route Documentation Priority

Document routes in this order of priority:

  1. Health Routes - /api/health/* (public, critical for operations)
  2. Auth Routes - /api/auth/* (public, essential for integration)
  3. Gamification Routes - /api/achievements/* (simple, good example)
  4. Flyer Routes - /api/flyers/* (core functionality)
  5. User Routes - /api/users/* (common CRUD patterns)
  6. Remaining Routes - Budget, Recipe, Admin, etc.

Swagger UI Setup

In server.ts, add the Swagger UI middleware (development/test only):

import swaggerUi from 'swagger-ui-express';
import { swaggerSpec } from './src/config/swagger';

// Only serve Swagger UI in non-production environments
if (process.env.NODE_ENV !== 'production') {
  app.use('/docs/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

  // Optionally expose raw JSON spec for tooling
  app.get('/docs/api-docs.json', (_req, res) => {
    res.setHeader('Content-Type', 'application/json');
    res.send(swaggerSpec);
  });
}

Response Schema Standardization

All API responses follow the standardized format from ADR-028:

// Success response
{
  "success": true,
  "data": { ... }
}

// Error response
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message"
  }
}

Define reusable schema components for these patterns:

/**
 * @openapi
 * components:
 *   schemas:
 *     SuccessResponse:
 *       type: object
 *       properties:
 *         success:
 *           type: boolean
 *           example: true
 *         data:
 *           type: object
 *     ErrorResponse:
 *       type: object
 *       properties:
 *         success:
 *           type: boolean
 *           example: false
 *         error:
 *           type: object
 *           properties:
 *             code:
 *               type: string
 *             message:
 *               type: string
 */

Security Considerations

  1. Production Disabled: Swagger UI is not available in production to prevent information disclosure.
  2. No Sensitive Data: Never include actual secrets, tokens, or PII in example values.
  3. Authentication Documented: Clearly document which endpoints require authentication.

API Route Tags

Organize endpoints using consistent tags:

Tag Description Routes
Health Server health and readiness checks /api/health/*
Auth Authentication and authorization /api/auth/*
Users User profile management /api/users/*
Flyers Flyer uploads and retrieval /api/flyers/*
Achievements Gamification and leaderboards /api/achievements/*
Budgets Budget tracking /api/budgets/*
Recipes Recipe management /api/recipes/*
Admin Administrative operations /api/admin/*
System System status and monitoring /api/system/*

Testing

Verify API documentation is correct by:

  1. Manual Review: Navigate to /docs/api-docs and test each endpoint.
  2. Spec Validation: Use OpenAPI validators to check the generated spec.
  3. Integration Tests: Existing integration tests serve as implicit documentation verification.

Consequences

Positive

  • Single Source of Truth: Documentation lives with the code and stays in sync.
  • Interactive Exploration: Developers can try endpoints directly from the UI.
  • SDK Generation: OpenAPI spec enables automatic client SDK generation.
  • Onboarding: New developers can quickly understand the API surface.
  • Low Overhead: JSDoc annotations are minimal additions to existing code.

Negative

  • Maintenance Required: Developers must update annotations when routes change.
  • Build Dependency: Adds swagger-jsdoc and swagger-ui-express packages.
  • Initial Investment: Existing routes need annotations added incrementally.

Mitigation

  • Include documentation checks in code review process.
  • Start with high-priority routes and expand coverage over time.
  • Use TypeScript types to reduce documentation duplication where possible.

Key Files

  • src/config/swagger.ts - OpenAPI configuration
  • src/routes/*.ts - Route files with JSDoc annotations
  • server.ts - Swagger UI middleware setup
  • ADR-003 - Input Validation (Zod schemas)
  • ADR-028 - Response Standardization
  • ADR-016 - Security Hardening