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.
This commit is contained in:
parent
25528811dc
commit
7e72871ad7
@ -6,48 +6,68 @@ import path from 'path';
|
|||||||
import util from 'util';
|
import util from 'util';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
if (!process.env.ENVIRONMENT) {
|
// Load environment variables
|
||||||
console.error("❌ Missing ENVIRONMENT variable.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
// Determine the environment
|
if (!process.env.ENVIRONMENT) {
|
||||||
const environment = process.env.ENVIRONMENT || 'dev';
|
console.error("❌ ENVIRONMENT variable is missing.");
|
||||||
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.");
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine environment and configuration file
|
||||||
|
const nodeEnv = process.env.ENVIRONMENT || 'dev';
|
||||||
|
const configFile = `config_${nodeEnv}.json`;
|
||||||
|
|
||||||
|
// Load configuration file
|
||||||
let config;
|
let config;
|
||||||
try {
|
try {
|
||||||
config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8'));
|
config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Error reading configuration file: ${error.message}`);
|
console.error(`❌ Failed to read configuration file '${configFile}': ${error.message}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.OPENAPI_URL || !config.SCHEMA_PATH || !config.OUTPUT_DIRECTORY || !config.SSL_KEY_PATH || !config.SSL_CERT_PATH) {
|
// Validate required configurations
|
||||||
console.error("❌ Missing essential configuration values.");
|
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve paths from the config
|
||||||
const OPENAPI_URL = config.OPENAPI_URL;
|
const OPENAPI_URL = config.OPENAPI_URL;
|
||||||
const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH);
|
const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH);
|
||||||
const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY);
|
const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY);
|
||||||
const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH);
|
const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH);
|
||||||
const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH);
|
const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH);
|
||||||
|
|
||||||
console.log(`Using SCHEMA_PATH: ${SCHEMA_PATH}`);
|
// Log configuration
|
||||||
console.log(`Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`);
|
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);
|
const execPromisified = util.promisify(exec);
|
||||||
|
|
||||||
let isGenerating = false;
|
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) {
|
function debounce(func, delay) {
|
||||||
let timer;
|
let timer;
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
@ -58,16 +78,17 @@ function debounce(func, delay) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main function to fetch OpenAPI schema and generate services
|
||||||
async function fetchAndGenerate() {
|
async function fetchAndGenerate() {
|
||||||
if (isGenerating) {
|
if (isGenerating) {
|
||||||
console.log("⚠️ Generation is already running.");
|
console.log("⚠️ Generation process is already running.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isGenerating = true;
|
isGenerating = true;
|
||||||
|
|
||||||
console.log("🚀 Fetching OpenAPI schema...");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Fetch OpenAPI schema over HTTPS
|
||||||
|
console.log("🚀 Fetching OpenAPI schema...");
|
||||||
const options = {
|
const options = {
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
key: fs.readFileSync(SSL_KEY_PATH),
|
key: fs.readFileSync(SSL_KEY_PATH),
|
||||||
@ -85,59 +106,58 @@ async function fetchAndGenerate() {
|
|||||||
|
|
||||||
res.on('end', async () => {
|
res.on('end', async () => {
|
||||||
try {
|
try {
|
||||||
|
// Save schema file
|
||||||
fs.writeFileSync(SCHEMA_PATH, data, 'utf8');
|
fs.writeFileSync(SCHEMA_PATH, data, 'utf8');
|
||||||
console.log(`✅ OpenAPI schema saved to ${SCHEMA_PATH}`);
|
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...");
|
console.log("🧼 Cleaning output directory...");
|
||||||
try {
|
|
||||||
await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true });
|
await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true });
|
||||||
console.log(`✅ Output directory cleaned at ${OUTPUT_DIRECTORY}`);
|
|
||||||
|
|
||||||
if (fs.existsSync(OUTPUT_DIRECTORY)) {
|
console.log(`✅ Output directory cleaned: ${OUTPUT_DIRECTORY}`);
|
||||||
console.error(`❌ Output directory still exists: ${OUTPUT_DIRECTORY}`);
|
if (!fs.existsSync(OUTPUT_DIRECTORY)) {
|
||||||
} else {
|
|
||||||
console.log(`✅ Confirmed removal of ${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}`;
|
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);
|
const { stdout, stderr } = await execPromisified(command);
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
console.error(`⚠️ stderr while generating services: ${stderr}`);
|
console.error(`⚠️ stderr while generating services: ${stderr}`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`✅ Command executed successfully, output:\n${stdout}`);
|
console.log(`✅ Service generation completed successfully:\n${stdout}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Error cleaning or executing command: ${error}`);
|
console.error(`❌ Error during schema processing or generation: ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
isGenerating = false;
|
isGenerating = false;
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error fetching OpenAPI schema: ' + error.message);
|
console.error(`❌ Failed to fetch OpenAPI schema: ${error.message}`);
|
||||||
isGenerating = false;
|
isGenerating = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define backendDirectory based on ENVIRONMENT variable
|
// Backend directory based on the environment
|
||||||
const ENVIRONMENT = process.env.ENVIRONMENT || 'dev';
|
const backendDirectory =
|
||||||
const backendDirectory = environment === 'test'
|
nodeEnv === 'test'
|
||||||
? path.resolve('/home/jungfrau/heidi-v2/backend/app')
|
? path.resolve('/home/jungfrau/heidi-v2/backend/app')
|
||||||
: path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app');
|
: path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app');
|
||||||
|
|
||||||
if (!backendDirectory) {
|
if (!fs.existsSync(backendDirectory)) {
|
||||||
console.error("❌ Failed to resolve backend directory path.");
|
console.error(`❌ Backend directory does not exist: ${backendDirectory}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log(`👀 Watching for changes in ${backendDirectory}`);
|
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
|
watcher
|
||||||
.on('add', debounce(fetchAndGenerate, debounceDelay))
|
.on('add', debounce(fetchAndGenerate, debounceDelay))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user