feat: form and proxy call
This commit is contained in:
63
server.js
63
server.js
@@ -1,6 +1,7 @@
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
@@ -19,6 +20,12 @@ function buildGraphFromPaths(pathsObject) {
|
||||
const nodes = [];
|
||||
const links = [];
|
||||
const endpoints = [];
|
||||
const operations = [];
|
||||
|
||||
// Add root node "/"
|
||||
const rootId = '/';
|
||||
nodeIdSet.add(rootId);
|
||||
nodes.push({ id: rootId });
|
||||
|
||||
for (const pathKey of Object.keys(pathsObject || {})) {
|
||||
const pathItem = pathsObject[pathKey] || {};
|
||||
@@ -26,6 +33,13 @@ function buildGraphFromPaths(pathsObject) {
|
||||
for (const method of Object.keys(pathItem)) {
|
||||
const lower = method.toLowerCase();
|
||||
if (httpMethods.has(lower)) {
|
||||
const op = pathItem[method] || {};
|
||||
const summary = op.summary || '';
|
||||
const description = op.description || '';
|
||||
const opParams = [].concat(pathItem.parameters || [], op.parameters || []).filter(Boolean);
|
||||
const parameters = opParams.map(p => ({ name: p.name, in: p.in, required: !!p.required, schema: p.schema || null }));
|
||||
const hasJsonBody = !!(op.requestBody && op.requestBody.content && op.requestBody.content['application/json']);
|
||||
operations.push({ method: lower.toUpperCase(), path: pathKey, summary, description, parameters, hasJsonBody });
|
||||
endpoints.push({ method: lower.toUpperCase(), path: pathKey });
|
||||
}
|
||||
}
|
||||
@@ -41,6 +55,16 @@ function buildGraphFromPaths(pathsObject) {
|
||||
}
|
||||
}
|
||||
|
||||
// Link from root "/" to first segment
|
||||
if (segments.length > 0) {
|
||||
const firstSeg = segments[0];
|
||||
const rootKey = `${rootId}|${firstSeg}`;
|
||||
if (!linkKeySet.has(rootKey)) {
|
||||
linkKeySet.add(rootKey);
|
||||
links.push({ source: rootId, target: firstSeg });
|
||||
}
|
||||
}
|
||||
|
||||
// Create sequential links along the path
|
||||
for (let i = 0; i < segments.length - 1; i++) {
|
||||
const source = segments[i];
|
||||
@@ -53,7 +77,7 @@ function buildGraphFromPaths(pathsObject) {
|
||||
}
|
||||
}
|
||||
|
||||
return { nodes, links, endpoints };
|
||||
return { nodes, links, endpoints, operations };
|
||||
}
|
||||
|
||||
app.post('/api/parse', (req, res) => {
|
||||
@@ -69,12 +93,47 @@ app.post('/api/parse', (req, res) => {
|
||||
|
||||
const pathsObject = spec.paths || {};
|
||||
const graph = buildGraphFromPaths(pathsObject);
|
||||
res.json({ graph, info: { title: spec.info && spec.info.title, version: spec.info && spec.info.version } });
|
||||
const servers = Array.isArray(spec.servers) ? spec.servers.map(s => s && s.url).filter(Boolean) : [];
|
||||
res.json({ graph, info: { title: spec.info && spec.info.title, version: spec.info && spec.info.version }, servers });
|
||||
} catch (err) {
|
||||
res.status(400).json({ error: err.message || 'Failed to parse YAML' });
|
||||
}
|
||||
});
|
||||
|
||||
// Simple proxy endpoint to call target server
|
||||
// Body: { baseUrl, method, path, headers, query, body }
|
||||
app.post('/api/proxy', async (req, res) => {
|
||||
try {
|
||||
const { baseUrl, method, path: relPath, headers = {}, query = {}, body } = req.body || {};
|
||||
if (!baseUrl || !method || !relPath) {
|
||||
return res.status(400).json({ error: 'Missing baseUrl, method, or path' });
|
||||
}
|
||||
const url = new URL(relPath.replace(/\s+/g, ''), baseUrl.endsWith('/') ? baseUrl : baseUrl + '/');
|
||||
for (const [k, v] of Object.entries(query || {})) {
|
||||
if (v !== undefined && v !== null && v !== '') url.searchParams.append(k, String(v));
|
||||
}
|
||||
const fetchOpts = { method: method.toUpperCase(), headers: { ...headers } };
|
||||
if (body !== undefined && body !== null && method.toUpperCase() !== 'GET') {
|
||||
if (!fetchOpts.headers['content-type'] && !fetchOpts.headers['Content-Type']) {
|
||||
fetchOpts.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
fetchOpts.body = typeof body === 'string' ? body : JSON.stringify(body);
|
||||
}
|
||||
const upstream = await fetch(url.toString(), fetchOpts);
|
||||
const contentType = upstream.headers.get('content-type') || '';
|
||||
res.status(upstream.status);
|
||||
if (contentType.includes('application/json')) {
|
||||
const data = await upstream.json().catch(() => null);
|
||||
res.json({ status: upstream.status, headers: Object.fromEntries(upstream.headers), data });
|
||||
} else {
|
||||
const text = await upstream.text();
|
||||
res.json({ status: upstream.status, headers: Object.fromEntries(upstream.headers), data: text });
|
||||
}
|
||||
} catch (err) {
|
||||
res.status(502).json({ error: err.message || 'Proxy request failed' });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server listening on http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user