import express from 'express'; import compression from 'compression'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const app = express(); const PORT = process.env.PORT || 3000; // Backend API URL - use Docker service name or environment variable const API_URL = process.env.API_URL || 'http://api:5000'; // Enable compression app.use(compression()); // Parse JSON bodies for proxied requests app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ extended: true, limit: '50mb' })); /** * API Proxy middleware * Forwards all /api/* requests to the backend service */ app.use('/api', async (req, res) => { const targetUrl = `${API_URL}${req.originalUrl}`; try { const fetchOptions = { method: req.method, headers: { 'Content-Type': req.get('Content-Type') || 'application/json', 'Accept': req.get('Accept') || 'application/json', }, }; // Forward body for POST/PUT/PATCH requests if (['POST', 'PUT', 'PATCH'].includes(req.method) && req.body) { fetchOptions.body = JSON.stringify(req.body); } const response = await fetch(targetUrl, fetchOptions); // Get content type from response const contentType = response.headers.get('content-type'); // Set response headers res.status(response.status); if (contentType) { res.set('Content-Type', contentType); } // Handle different response types if (contentType && (contentType.includes('application/pdf') || contentType.includes('text/plain') || contentType.includes('application/octet-stream'))) { // Binary/file responses const buffer = await response.arrayBuffer(); res.send(Buffer.from(buffer)); } else { // JSON responses const data = await response.text(); res.send(data); } } catch (error) { console.error(`API Proxy Error [${req.method} ${req.originalUrl}]:`, error.message); res.status(502).json({ status: 'error', message: 'Failed to connect to backend service', details: error.message }); } }); // Serve static files from build directory const buildPath = path.join(__dirname, '../build'); app.use(express.static(buildPath)); // SPA fallback - serve index.html for all other routes app.get('*', (req, res) => { res.sendFile(path.join(buildPath, 'index.html')); }); app.listen(PORT, '0.0.0.0', () => { console.log(`Frontend server running on http://localhost:${PORT}`); console.log(`API proxy target: ${API_URL}`); });