UNPKG

api-explorer-cli

Version:

A CLI tool to proxy localhost API requests for the API Explorer web app

155 lines (138 loc) 4.39 kB
#!/usr/bin/env node import express from 'express'; import axios from 'axios'; import cors from 'cors'; import { URLSearchParams } from 'url'; const app = express(); const port = 9999; // Middleware to enable CORS app.use(cors({ origin: 'https://apiexplorer.vercel.app', // Replace with your Vercel domain })); app.use(express.json()); // Proxy endpoint to forward requests to localhost app.post('/proxy', async (req, res) => { const { method, url, headers = [], params = [], body, bodyType, authType, authData = {}, } = req.body; // Validate localhost URL if (!url || !url.startsWith('http://localhost')) { return res.status(400).json({ statusCode: 400, statusText: 'Bad Request', responseTime: 0, headers: {}, body: 'Invalid or non-localhost URL provided', size: 0, }); } try { // Prepare headers const requestHeaders = {}; headers .filter((header) => header.enabled) .forEach((header) => { requestHeaders[header.name] = header.value; }); // Add authentication headers if (authType === 'bearer' && authData.token) { requestHeaders['Authorization'] = `Bearer ${authData.token}`; } else if (authType === 'basic' && authData.username && authData.password) { requestHeaders['Authorization'] = `Basic ${Buffer.from( `${authData.username}:${authData.password}` ).toString('base64')}`; } // Prepare query parameters const requestParams = {}; params .filter((param) => param.enabled) .forEach((param) => { requestParams[param.name] = param.value; }); // Prepare request data based on bodyType let requestData; if (['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) { switch (bodyType) { case 'form-data': requestData = body; delete requestHeaders['Content-Type']; break; case 'x-www-form-urlencoded': requestData = new URLSearchParams(); body.forEach((field) => { requestData.append(field.key, field.value); }); requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded'; break; case 'raw': requestData = body; break; case 'GraphQL': requestData = body; requestHeaders['Content-Type'] = 'application/json'; break; case 'binary': requestData = body; requestHeaders['Content-Type'] = 'application/octet-stream'; break; default: requestData = undefined; } } // Axios configuration const config = { method: method.toUpperCase(), url, headers: requestHeaders, params: requestParams, data: requestData, timeout: 30000, validateStatus: () => true, }; // Measure response time const startTime = Date.now(); const response = await axios(config); const responseTime = Date.now() - startTime; // Calculate response size const responseBody = response.data; const size = Buffer.byteLength( typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody) ); // Prepare response const responseData = { statusCode: response.status, statusText: response.statusText, responseTime, headers: response.headers, body: typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody, null, 2), size, }; res.json(responseData); } catch (error) { console.error('Proxy request failed:', error); const errorResponse = { statusCode: error.response?.status || 500, statusText: error.response?.statusText || 'Internal Server Error', responseTime: 0, headers: error.response?.headers || {}, body: error.message || 'Proxy request failed', size: 0, }; res.status(errorResponse.statusCode).json(errorResponse); } }); // Start the proxy server app.listen(port, () => { console.log(`API Explorer Proxy running at http://localhost:${port}`); console.log('Use this in your API Explorer to forward localhost requests.'); });