UNPKG

@flavoai/fastfold

Version:

Zero-boilerplate backend for React apps with auto-generated CRUD and declarative security

307 lines 11.5 kB
export class ApiDocumentationGenerator { config; constructor(config) { this.config = config; } /** * Generate complete API documentation */ generateDocumentation() { const tables = this.config.tables; const endpoints = []; // Add health endpoint endpoints.push({ method: 'GET', path: '/health', description: 'Health check endpoint', responses: [ { status: 200, description: 'Server is healthy', schema: { type: 'object', properties: { status: { type: 'string', example: 'healthy' }, timestamp: { type: 'string', example: '2024-01-01T00:00:00.000Z' } } } } ] }); // Generate endpoints for each table for (const [tableName, tableDefinition] of Object.entries(tables)) { const tableEndpoints = this.generateTableEndpoints(tableName, tableDefinition); endpoints.push(...tableEndpoints); } return { info: { title: 'Fastfold API', description: 'Auto-generated CRUD API with declarative security', version: '1.0.0', baseUrl: 'http://localhost:' + (this.config.port || 3001) }, tables: Object.fromEntries(Object.entries(tables).map(([name, def]) => [ name, { schema: def.schema, security: this.getSecurityDescription(def.security) } ])), endpoints }; } /** * Generate endpoints for a specific table */ generateTableEndpoints(tableName, tableDefinition) { const basePath = `/api/${tableName}`; const schema = tableDefinition.schema; const endpoints = []; // GET /api/:table - List records endpoints.push({ method: 'GET', path: basePath, description: `List all ${tableName} records with optional filtering, sorting, and pagination`, parameters: [ { name: 'params', in: 'query', required: false, type: 'string', description: 'JSON string with query parameters (where, orderBy, take, skip)' } ], responses: [ { status: 200, description: 'List of records', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: { type: 'array', items: this.schemaToJsonSchema(schema) }, count: { type: 'number', example: 10 } } } }, { status: 403, description: 'Forbidden - Security check failed' } ] }); // GET /api/:table/:id - Get single record endpoints.push({ method: 'GET', path: `${basePath}/{id}`, description: `Get a specific ${tableName} record by ID`, parameters: [ { name: 'id', in: 'path', required: true, type: 'string', description: 'Record ID' } ], responses: [ { status: 200, description: 'Single record', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: this.schemaToJsonSchema(schema) } } }, { status: 404, description: 'Record not found' }, { status: 403, description: 'Forbidden - Security check failed' } ] }); // POST /api/:table - Create record endpoints.push({ method: 'POST', path: basePath, description: `Create a new ${tableName} record`, requestBody: { description: `${tableName} data to create`, schema: this.schemaToJsonSchema(schema) }, responses: [ { status: 201, description: 'Record created successfully', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: this.schemaToJsonSchema(schema) } } }, { status: 400, description: 'Validation error' }, { status: 403, description: 'Forbidden - Security check failed' } ] }); // PUT /api/:table/:id - Update record endpoints.push({ method: 'PUT', path: `${basePath}/{id}`, description: `Update a ${tableName} record`, parameters: [ { name: 'id', in: 'path', required: true, type: 'string', description: 'Record ID' } ], requestBody: { description: `${tableName} data to update`, schema: this.schemaToJsonSchema(schema) }, responses: [ { status: 200, description: 'Record updated successfully', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: this.schemaToJsonSchema(schema) } } }, { status: 404, description: 'Record not found' }, { status: 400, description: 'Validation error' }, { status: 403, description: 'Forbidden - Security check failed' } ] }); // DELETE /api/:table/:id - Delete record endpoints.push({ method: 'DELETE', path: `${basePath}/{id}`, description: `Delete a ${tableName} record`, parameters: [ { name: 'id', in: 'path', required: true, type: 'string', description: 'Record ID' } ], responses: [ { status: 200, description: 'Record deleted successfully', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: { type: 'object', properties: { deleted: { type: 'boolean', example: true } } } } } }, { status: 404, description: 'Record not found' }, { status: 403, description: 'Forbidden - Security check failed' } ] }); // GET /api/:table/count - Count records endpoints.push({ method: 'GET', path: `${basePath}/count`, description: `Count ${tableName} records with optional filtering`, parameters: [ { name: 'where', in: 'query', required: false, type: 'string', description: 'JSON string with filter conditions' } ], responses: [ { status: 200, description: 'Record count', schema: { type: 'object', properties: { success: { type: 'boolean', example: true }, data: { type: 'object', properties: { count: { type: 'number', example: 42 } } } } } }, { status: 403, description: 'Forbidden - Security check failed' } ] }); return endpoints; } /** * Convert Fastfold schema to JSON Schema */ schemaToJsonSchema(schema) { const properties = {}; for (const [fieldName, fieldType] of Object.entries(schema)) { switch (fieldType) { case 'string': properties[fieldName] = { type: 'string', example: `sample_${fieldName}` }; break; case 'number': properties[fieldName] = { type: 'number', example: 42 }; break; case 'boolean': properties[fieldName] = { type: 'boolean', example: true }; break; case 'date': properties[fieldName] = { type: 'string', format: 'date-time', example: '2024-01-01T00:00:00.000Z' }; break; case 'json': properties[fieldName] = { type: 'object', example: { key: 'value' } }; break; default: properties[fieldName] = { type: 'string', example: `sample_${fieldName}` }; } } return { type: 'object', properties, example: Object.fromEntries(Object.entries(properties).map(([key, value]) => [key, value.example])) }; } /** * Get human-readable security description */ getSecurityDescription(security) { if (!security) return 'No security configured'; // This is a simplified version - in a real implementation, // you'd need to inspect the security object more thoroughly if (security.type === 'public') return 'Public access - no authentication required'; if (security.type === 'admin') return 'Admin only - requires admin role'; if (security.type === 'owner') return `Owner-based access - users can only access their own records`; if (security.type === 'team') return `Team-based access - users can access records from their team`; if (security.type === 'authenticated') return 'Authenticated users only'; return 'Custom security rule'; } } //# sourceMappingURL=generator.js.map