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:
- Developer Experience: Developers need interactive documentation to explore and test API endpoints.
- Code-Documentation Sync: Documentation should stay in sync with the actual code to prevent drift.
- Low Maintenance Overhead: The documentation approach should be "fast and lite" - minimal additional work for developers.
- 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:
- JSDoc Annotations: Use
swagger-jsdocto generate OpenAPI specs from JSDoc comments in route files. - Swagger UI: Use
swagger-ui-expressto serve interactive documentation at/docs/api-docs. - Environment Restriction: Only expose the Swagger UI in development and test environments, not production.
- 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:
- Health Routes -
/api/health/*(public, critical for operations) - Auth Routes -
/api/auth/*(public, essential for integration) - Gamification Routes -
/api/achievements/*(simple, good example) - Flyer Routes -
/api/flyers/*(core functionality) - User Routes -
/api/users/*(common CRUD patterns) - 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
- Production Disabled: Swagger UI is not available in production to prevent information disclosure.
- No Sensitive Data: Never include actual secrets, tokens, or PII in example values.
- 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:
- Manual Review: Navigate to
/docs/api-docsand test each endpoint. - Spec Validation: Use OpenAPI validators to check the generated spec.
- 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-jsdocandswagger-ui-expresspackages. - 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 configurationsrc/routes/*.ts- Route files with JSDoc annotationsserver.ts- Swagger UI middleware setup