Files
Hoya26/frontend/server/index.js
2026-01-26 10:11:17 +00:00

89 lines
2.8 KiB
JavaScript

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}`);
});