96 lines
3.2 KiB
JavaScript
96 lines
3.2 KiB
JavaScript
/**
|
|
* @cc-platform/server/proxy — Cross-service integration proxy
|
|
*
|
|
* Extracted from the reciprocal proxy endpoints in both servers:
|
|
* remoteturtle: /api/integration/inventory-locate → INVENTORY_SERVER_URL
|
|
* inventory-manager: /api/integration/turtle-status → TURTLE_SERVER_URL
|
|
*
|
|
* Both use the exact same pattern: check URL configured → fetch → forward JSON.
|
|
*
|
|
* Usage:
|
|
* const { proxyRequest, createProxyEndpoint } = require('@cc-platform/server/proxy');
|
|
*
|
|
* // One-off proxy call
|
|
* const result = await proxyRequest('http://other-server:3001', '/api/items', { q: 'diamond' });
|
|
*
|
|
* // Register a proxy endpoint on Express
|
|
* createProxyEndpoint(app, '/api/integration/items', 'INVENTORY_SERVER_URL', '/api/integration/items');
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
/**
|
|
* Proxy a request to a remote service, returning JSON.
|
|
*
|
|
* @param {string} baseUrl - Base URL of the remote service (e.g. 'http://localhost:3001')
|
|
* @param {string} remotePath - Path on the remote service (e.g. '/api/items')
|
|
* @param {Object} [query={}] - Query parameters to forward
|
|
* @param {Object} [options={}] - Additional options
|
|
* @param {number} [options.timeoutMs=5000] - Request timeout in milliseconds
|
|
* @returns {Promise<Object>} Parsed JSON response, or error/unconfigured object
|
|
*/
|
|
async function proxyRequest(baseUrl, remotePath, query = {}, options = {}) {
|
|
if (!baseUrl) {
|
|
return {
|
|
configured: false,
|
|
message: 'Integration not configured — remote service URL not set',
|
|
};
|
|
}
|
|
|
|
const timeoutMs = options.timeoutMs || 5000;
|
|
|
|
try {
|
|
const params = new URLSearchParams(query).toString();
|
|
const url = params
|
|
? `${baseUrl}${remotePath}?${params}`
|
|
: `${baseUrl}${remotePath}`;
|
|
|
|
const resp = await fetch(url, {
|
|
signal: AbortSignal.timeout(timeoutMs),
|
|
});
|
|
|
|
if (!resp.ok) {
|
|
return {
|
|
error: `Remote service returned ${resp.status}: ${resp.statusText}`,
|
|
status: resp.status,
|
|
};
|
|
}
|
|
|
|
return await resp.json();
|
|
} catch (e) {
|
|
return {
|
|
error: `Integration unavailable: ${e.message}`,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register a proxy endpoint on an Express app.
|
|
*
|
|
* Creates a GET endpoint at `localPath` that proxies requests to
|
|
* `remotePath` on the service URL specified by the given environment variable.
|
|
*
|
|
* @param {Express.Application} app - Express app instance
|
|
* @param {string} localPath - Local endpoint path (e.g. '/api/integration/items')
|
|
* @param {string} remoteBaseUrlEnvVar - Env var name for the remote URL (e.g. 'INVENTORY_SERVER_URL')
|
|
* @param {string} remotePath - Path on the remote service (e.g. '/api/integration/items')
|
|
* @param {Object} [options={}] - proxyRequest options
|
|
* @returns {string} The resolved base URL (for logging)
|
|
*/
|
|
function createProxyEndpoint(app, localPath, remoteBaseUrlEnvVar, remotePath, options = {}) {
|
|
const baseUrl = process.env[remoteBaseUrlEnvVar] || '';
|
|
|
|
app.get(localPath, async (req, res) => {
|
|
try {
|
|
const result = await proxyRequest(baseUrl, remotePath, req.query, options);
|
|
res.json(result);
|
|
} catch (e) {
|
|
res.status(500).json({ error: e.message });
|
|
}
|
|
});
|
|
|
|
return baseUrl;
|
|
}
|
|
|
|
module.exports = { proxyRequest, createProxyEndpoint };
|