UNPKG

express-gateway

Version:

A microservices API gateway built on top of ExpressJS

104 lines (91 loc) 3.41 kB
const logger = require('./logger').plugins; const eventBus = require('./eventBus'); const schemas = require('./schemas'); const parentRequire = require('parent-require'); const engineVersion = '1.2.0'; const semver = require('semver'); const prefix = 'express-gateway-plugin-'; // TODO make configurable module.exports.load = function ({ config }) { config = config || require('./config'); const pluginsSettings = config.systemConfig.plugins || {}; const loadedPlugins = []; logger.debug(`Loading plugins. Plugin engine version: ${engineVersion}`); for (const pluginName in pluginsSettings) { const settings = pluginsSettings[pluginName] || {}; let requireName = pluginName; if (settings.package) { requireName = settings.package; } else if (pluginName.indexOf(prefix) !== 0) { requireName = prefix + pluginName; } try { logger.debug(`Loading plugin ${requireName}`); let plugin; try { plugin = require(requireName); // EG loaded as main module } catch (err) { plugin = parentRequire(requireName); // EG loaded as library (after eg gateway create) } if (semver.lt(engineVersion, plugin.version)) { // TODO: versioning of plugins logger.warn(`${plugin.version} is higher than engine version: ${engineVersion}; trying to load`); } // register schema and validate settings const validate = schemas.register('plugin', pluginName, plugin.schema); const { isValid, error } = validate(settings); if (!isValid) { // Stop loading plugin. throw new Error(`Failed to validate settings: ${error}`); } const services = require('./services'); const context = new PluginContext({ settings, config, services }); plugin.init(context); loadedPlugins.push(context); logger.info(`Loaded plugin ${pluginName} from package ${requireName}`); } catch (err) { logger.error(`Failed to load plugin ${requireName}: ${err}`); } } // Note: All logic to handle different plugin version should be here // Note: Rest of EG code must use only one standard interface return { policies: extract(loadedPlugins, 'policies'), conditions: extract(loadedPlugins, 'conditions'), gatewayRoutes: extract(loadedPlugins, 'gatewayRoutes'), adminRoutes: extract(loadedPlugins, 'adminRoutes'), cliExtensions: extract(loadedPlugins, 'cliExtensions') }; }; class PluginContext { constructor ({ settings, config, services }) { this.logger = logger; this.services = services; this.settings = settings || {}; this.config = config; this.policies = []; this.conditions = []; this.gatewayRoutes = []; this.adminRoutes = []; this.cliExtensions = []; this.eventBus = eventBus; } registerPolicy (policy) { this.policies.push(policy); } registerCondition (condition) { this.conditions.push(condition); } registerGatewayRoute (gatewayRoutesDeclaration) { this.gatewayRoutes.push(gatewayRoutesDeclaration); } registerAdminRoute (adminRoutesDeclaration) { this.adminRoutes.push(adminRoutesDeclaration); } registerCLIExtension (cliExtension) { this.cliExtensions.push(cliExtension); } } function extract (loadedPlugins, propName) { return loadedPlugins.reduce((result, current) => { return result.concat(current[propName] || []); }, []); };