import Fastify from 'fastify'; import cors from '@fastify/cors'; import helmet from '@fastify/helmet'; import { authMiddleware } from './middleware/auth.middleware'; import { rateLimitMiddleware } from './middleware/rate-limit.middleware'; import { spamRateLimitMiddleware } from './middleware/spam-rate-limit.middleware'; import { errorHandlingMiddleware } from './middleware/error-handling.middleware'; import { loggingMiddleware } from './middleware/logging.middleware'; import { apiEnv, loggingConfig } from './config/api.config'; import { routes } from './routes'; const fastify = Fastify({ logger: loggingConfig, ignoreTrailingSlash: true, maxParamLength: 500, }); // Register plugins async function registerPlugins() { // CORS configuration await fastify.register(cors, { origin: apiEnv.CORS_ORIGIN, methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], credentials: true, }); // Security headers await fastify.register(helmet, { global: true, contentSecurityPolicy: false, }); // Rate limiting await fastify.register(rateLimitMiddleware); // SpamShield rate limiting (Redis-backed) await fastify.register(spamRateLimitMiddleware); // Authentication await fastify.register(authMiddleware); // Logging await fastify.register(loggingMiddleware); // Error handling await fastify.register(errorHandlingMiddleware); } // Register routes async function registerRoutes() { await fastify.register(routes, { prefix: '/api/v1' }); } // Health check endpoint fastify.get('/health', async () => { return { status: 'ok', timestamp: new Date().toISOString() }; }); // Root endpoint fastify.get('/', async () => { return { name: 'FrenoCorp API Gateway', version: '1.0.0', environment: apiEnv.NODE_ENV, }; }); // Start server async function start() { await registerPlugins(); await registerRoutes(); try { await fastify.listen({ port: apiEnv.PORT, host: apiEnv.HOST, }); console.log(`šŸš€ API Gateway running at http://${apiEnv.HOST}:${apiEnv.PORT}`); console.log(`šŸ“ Environment: ${apiEnv.NODE_ENV}`); console.log(`šŸ“Š Rate limit window: ${apiEnv.API_RATE_LIMIT_WINDOW}ms`); console.log(`šŸ“ˆ Max requests: ${apiEnv.API_RATE_LIMIT_MAX_REQUESTS}`); } catch (err) { console.error(err); process.exit(1); } } // Graceful shutdown const gracefulShutdown = async (signal: string) => { console.log(`\nšŸ›‘ ${signal} received, shutting down gracefully...`); await fastify.close(); console.log('āœ… Server closed'); process.exit(0); }; process.on('SIGINT', () => gracefulShutdown('SIGINT')); process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); // Export for testing export { fastify }; // Start if running directly if (process.argv[1] === new URL(import.meta.url).pathname) { start(); }