Files
flyer-crawler.projectium.com/src/config/swagger.ts
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

229 lines
5.9 KiB
TypeScript

// src/config/swagger.ts
/**
* @file OpenAPI/Swagger configuration for API documentation.
* Implements ADR-018: API Documentation Strategy.
*
* This file configures swagger-jsdoc to generate an OpenAPI 3.0 specification
* from JSDoc annotations in route files. The specification is used by
* swagger-ui-express to serve interactive API documentation.
*/
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 - a platform for discovering grocery deals, managing recipes, and tracking budgets.',
contact: {
name: 'API Support',
},
license: {
name: 'Private',
},
},
servers: [
{
url: '/api',
description: 'API server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: 'JWT token obtained from /auth/login or /auth/register',
},
},
schemas: {
// Standard success response wrapper (ADR-028)
SuccessResponse: {
type: 'object',
properties: {
success: {
type: 'boolean',
example: true,
},
data: {
type: 'object',
description: 'Response payload - structure varies by endpoint',
},
},
required: ['success', 'data'],
},
// Standard error response wrapper (ADR-028)
ErrorResponse: {
type: 'object',
properties: {
success: {
type: 'boolean',
example: false,
},
error: {
type: 'object',
properties: {
code: {
type: 'string',
description: 'Machine-readable error code',
example: 'VALIDATION_ERROR',
},
message: {
type: 'string',
description: 'Human-readable error message',
example: 'Invalid request parameters',
},
},
required: ['code', 'message'],
},
},
required: ['success', 'error'],
},
// Common service health status
ServiceHealth: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['healthy', 'degraded', 'unhealthy'],
},
latency: {
type: 'number',
description: 'Response time in milliseconds',
},
message: {
type: 'string',
description: 'Additional status information',
},
details: {
type: 'object',
description: 'Service-specific details',
},
},
required: ['status'],
},
// Achievement schema
Achievement: {
type: 'object',
properties: {
achievement_id: {
type: 'integer',
example: 1,
},
name: {
type: 'string',
example: 'First-Upload',
},
description: {
type: 'string',
example: 'Upload your first flyer',
},
icon: {
type: 'string',
example: 'upload-cloud',
},
points_value: {
type: 'integer',
example: 25,
},
created_at: {
type: 'string',
format: 'date-time',
},
},
},
// User achievement (with achieved_at)
UserAchievement: {
allOf: [
{ $ref: '#/components/schemas/Achievement' },
{
type: 'object',
properties: {
user_id: {
type: 'string',
format: 'uuid',
},
achieved_at: {
type: 'string',
format: 'date-time',
},
},
},
],
},
// Leaderboard entry
LeaderboardUser: {
type: 'object',
properties: {
user_id: {
type: 'string',
format: 'uuid',
},
full_name: {
type: 'string',
example: 'John Doe',
},
avatar_url: {
type: 'string',
nullable: true,
},
points: {
type: 'integer',
example: 150,
},
rank: {
type: 'integer',
example: 1,
},
},
},
},
},
tags: [
{
name: 'Health',
description: 'Server health and readiness checks',
},
{
name: 'Auth',
description: 'Authentication and authorization',
},
{
name: 'Users',
description: 'User profile management',
},
{
name: 'Achievements',
description: 'Gamification and leaderboards',
},
{
name: 'Flyers',
description: 'Flyer uploads and retrieval',
},
{
name: 'Recipes',
description: 'Recipe management',
},
{
name: 'Budgets',
description: 'Budget tracking and analysis',
},
{
name: 'Admin',
description: 'Administrative operations (requires admin role)',
},
{
name: 'System',
description: 'System status and monitoring',
},
],
},
// Path to the API routes files with JSDoc annotations
apis: ['./src/routes/*.ts'],
};
export const swaggerSpec = swaggerJsdoc(options);