# 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`: ```typescript 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: ```typescript /** * @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): ```typescript 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](./0028-api-response-standardization.md): ```typescript // Success response { "success": true, "data": { ... } } // Error response { "success": false, "error": { "code": "ERROR_CODE", "message": "Human-readable message" } } ``` Define reusable schema components for these patterns: ```typescript /** * @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 ## Related ADRs - [ADR-003](./0003-standardized-input-validation-using-middleware.md) - Input Validation (Zod schemas) - [ADR-028](./0028-api-response-standardization.md) - Response Standardization - [ADR-016](./0016-api-security-hardening.md) - Security Hardening