From 7e72871ad7e7f569fefe1d9af2364c3cac86ef1c Mon Sep 17 00:00:00 2001 From: GotthardG <51994228+GotthardG@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:38:26 +0100 Subject: [PATCH] Refactor OpenAPI fetcher for improved clarity and robustness Reorganized and enhanced the OpenAPI fetch logic for better maintainability and error handling. Key updates include improved environment variable validation, more detailed error messages, streamlined configuration loading, and additional safety checks for file paths and directories. Added proper logging and ensured the process flow is easy to trace. --- frontend/fetch-openapi.js | 112 ++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/frontend/fetch-openapi.js b/frontend/fetch-openapi.js index ed0002a..b468a86 100644 --- a/frontend/fetch-openapi.js +++ b/frontend/fetch-openapi.js @@ -6,48 +6,68 @@ import path from 'path'; import util from 'util'; import dotenv from 'dotenv'; -if (!process.env.ENVIRONMENT) { - console.error("❌ Missing ENVIRONMENT variable."); - process.exit(1); -} +// Load environment variables dotenv.config(); -// Determine the environment -const environment = process.env.ENVIRONMENT || 'dev'; -const nodeEnv = process.env.NODE_ENV || 'dev'; -const configFile = `config_${nodeEnv}.json`; - -// Load the appropriate configuration -if (!configFile) { - console.error("❌ Configuration file path is missing."); +if (!process.env.ENVIRONMENT) { + console.error("❌ ENVIRONMENT variable is missing."); process.exit(1); } + +// Determine environment and configuration file +const nodeEnv = process.env.ENVIRONMENT || 'dev'; +const configFile = `config_${nodeEnv}.json`; + +// Load configuration file let config; try { config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8')); } catch (error) { - console.error(`❌ Error reading configuration file: ${error.message}`); + console.error(`❌ Failed to read configuration file '${configFile}': ${error.message}`); process.exit(1); } -if (!config.OPENAPI_URL || !config.SCHEMA_PATH || !config.OUTPUT_DIRECTORY || !config.SSL_KEY_PATH || !config.SSL_CERT_PATH) { - console.error("❌ Missing essential configuration values."); - process.exit(1); +// Validate required configurations +const requiredFields = [ + 'OPENAPI_URL', + 'SCHEMA_PATH', + 'OUTPUT_DIRECTORY', + 'SSL_KEY_PATH', + 'SSL_CERT_PATH', +]; +for (const field of requiredFields) { + if (!config[field]) { + console.error(`❌ Missing required configuration: ${field}`); + process.exit(1); + } } + +// Resolve paths from the config const OPENAPI_URL = config.OPENAPI_URL; const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH); const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY); const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH); const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH); -console.log(`Using SCHEMA_PATH: ${SCHEMA_PATH}`); -console.log(`Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`); +// Log configuration +console.log(`[INFO] Environment: ${nodeEnv}`); +console.log(`[INFO] Using SCHEMA_PATH: ${SCHEMA_PATH}`); +console.log(`[INFO] Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`); + +// Verify SSL files +if (!fs.existsSync(SSL_KEY_PATH) || !fs.existsSync(SSL_CERT_PATH)) { + console.error(`❌ SSL files not found: + Key Path: ${SSL_KEY_PATH} (exists: ${fs.existsSync(SSL_KEY_PATH)}) + Cert Path: ${SSL_CERT_PATH} (exists: ${fs.existsSync(SSL_CERT_PATH)})`); + process.exit(1); +} const execPromisified = util.promisify(exec); let isGenerating = false; -const debounceDelay = 500; // 500ms debounce +const debounceDelay = 500; // Debounce interval in milliseconds +// Debounce function to control rapid re-triggering function debounce(func, delay) { let timer; return (...args) => { @@ -58,16 +78,17 @@ function debounce(func, delay) { }; } +// Main function to fetch OpenAPI schema and generate services async function fetchAndGenerate() { if (isGenerating) { - console.log("⚠️ Generation is already running."); + console.log("⚠️ Generation process is already running."); return; } isGenerating = true; - console.log("🚀 Fetching OpenAPI schema..."); - try { + // Fetch OpenAPI schema over HTTPS + console.log("🚀 Fetching OpenAPI schema..."); const options = { rejectUnauthorized: false, key: fs.readFileSync(SSL_KEY_PATH), @@ -85,59 +106,58 @@ async function fetchAndGenerate() { res.on('end', async () => { try { + // Save schema file fs.writeFileSync(SCHEMA_PATH, data, 'utf8'); console.log(`✅ OpenAPI schema saved to ${SCHEMA_PATH}`); - } catch (writeError) { - console.error(`❌ Error saving OpenAPI schema: ${writeError}`); - isGenerating = false; - return; - } - console.log("🧼 Cleaning output directory..."); - try { + console.log("🧼 Cleaning output directory..."); await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true }); - console.log(`✅ Output directory cleaned at ${OUTPUT_DIRECTORY}`); - if (fs.existsSync(OUTPUT_DIRECTORY)) { - console.error(`❌ Output directory still exists: ${OUTPUT_DIRECTORY}`); - } else { + console.log(`✅ Output directory cleaned: ${OUTPUT_DIRECTORY}`); + if (!fs.existsSync(OUTPUT_DIRECTORY)) { console.log(`✅ Confirmed removal of ${OUTPUT_DIRECTORY}`); + } else { + console.error(`❌ Failed to remove output directory: ${OUTPUT_DIRECTORY}`); } + // Generate services const command = `npx openapi -i ${SCHEMA_PATH} -o ${OUTPUT_DIRECTORY}`; - console.log(`Executing debug command: ${command}`); + console.log(`🔧 Executing command: ${command}`); const { stdout, stderr } = await execPromisified(command); if (stderr) { console.error(`⚠️ stderr while generating services: ${stderr}`); } else { - console.log(`✅ Command executed successfully, output:\n${stdout}`); + console.log(`✅ Service generation completed successfully:\n${stdout}`); } } catch (error) { - console.error(`❌ Error cleaning or executing command: ${error}`); + console.error(`❌ Error during schema processing or generation: ${error.message}`); } - isGenerating = false; }); } catch (error) { - console.error('❌ Error fetching OpenAPI schema: ' + error.message); + console.error(`❌ Failed to fetch OpenAPI schema: ${error.message}`); isGenerating = false; } } -// Define backendDirectory based on ENVIRONMENT variable -const ENVIRONMENT = process.env.ENVIRONMENT || 'dev'; -const backendDirectory = environment === 'test' - ? path.resolve('/home/jungfrau/heidi-v2/backend/app') - : path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app'); +// Backend directory based on the environment +const backendDirectory = + nodeEnv === 'test' + ? path.resolve('/home/jungfrau/heidi-v2/backend/app') + : path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app'); -if (!backendDirectory) { - console.error("❌ Failed to resolve backend directory path."); +if (!fs.existsSync(backendDirectory)) { + console.error(`❌ Backend directory does not exist: ${backendDirectory}`); process.exit(1); } console.log(`👀 Watching for changes in ${backendDirectory}`); -const watcher = chokidar.watch(backendDirectory, { persistent: true, ignored: [SCHEMA_PATH, OUTPUT_DIRECTORY] }); +// Watcher for change detection +const watcher = chokidar.watch(backendDirectory, { + persistent: true, + ignored: [SCHEMA_PATH, OUTPUT_DIRECTORY], +}); watcher .on('add', debounce(fetchAndGenerate, debounceDelay))