UNPKG

express-gateway

Version:

A microservices API gateway built on top of ExpressJS

175 lines (141 loc) 5.27 kB
const Generator = require('yeoman-generator'); const chalk = require('chalk'); const config = require('../lib/config'); const { validate, find } = require('../lib/schemas'); module.exports = class EgGenerator extends Generator { constructor (args, opts) { super(args, opts); this._configuration = null; this.eg = this.env.eg; this.argv = this.env.argv; this.admin = require('../admin')({ baseUrl: this._getAdminClientBaseURL(), verbose: this._getAdminClientVerboseFlag(), headers: this.argv && this.argv.H ? this.processHeaders(this.argv.H) : null }); } configureCommand (configuration) { const builder = configuration.builder; configuration.builder = yargs => { return this._wrapConfig(builder(yargs)); }; configuration.handler = argv => { this.env.argv = argv; const command = this.options.env.commandAliases[0][argv._[0]]; const subCommand = this.options.env.commandAliases[1][command][argv._[1]]; this.env.run(`express-gateway:${command}:${subCommand}`); }; this._configuration = configuration; } stdout (...args) { // eslint-disable-next-line no-console console.log.apply(console, args); } createSubCommand (name) { const generatorName = `${this.constructor.namespace}:${name}`; return this.env.create(generatorName)._configuration; } // configuration defaults _wrapConfig (yargs) { return yargs .boolean(['no-color', 'q', 'v']) .string(['H']) .describe('no-color', 'Disable color in prompts') .alias('q', 'quiet') .describe('q', 'Only show major pieces of output') .describe('H', 'Header to send with each request to Express Gateway Admin API KEY:VALUE format') .alias('v', 'verbose') .describe('v', 'Verbose output, will show request to Admin API') .group(['no-color', 'q'], 'Options:'); } _getAdminClientBaseURL () { const gatewayConfig = config.gatewayConfig; const systemConfig = config.systemConfig; let baseURL = 'http://localhost:9876'; // fallback default if (process.env.EG_ADMIN_URL) { baseURL = process.env.EG_ADMIN_URL; } else if (systemConfig && systemConfig.cli && systemConfig.cli.url) { baseURL = systemConfig.cli.url; } else if (gatewayConfig && gatewayConfig.admin) { const adminConfig = gatewayConfig.admin; const host = adminConfig.host || adminConfig.hostname || 'localhost'; const port = adminConfig.port || 9876; baseURL = `http://${host}:${port}`; } /* This bad hack is required because of the weird way superagent is managing urls. Hopefully this is not going to be here forever — we'll replace the client with Axios hopefully. Ref: https://github.com/ExpressGateway/express-gateway/issues/672 */ if (baseURL.endsWith('/')) { baseURL = baseURL.substr(0, baseURL.length - 1); } return baseURL; } _getAdminClientVerboseFlag () { let verbose = false; // default if (this.argv && this.argv.v) { verbose = this.argv.v; } else if (config.systemConfig && config.systemConfig.cli) { verbose = !!config.systemConfig.cli.verbose; } return verbose; } processHeaders (headers) { const ArrayHeaders = Array.isArray(headers) ? headers : [headers]; return ArrayHeaders.reduce((prev, header) => { const [headerName, headerValue] = header.split(/:(.+)/); if (headerValue) { prev[headerName] = headerValue; } return prev; }, {}); } _promptAndValidate (object, schema, { skipPrompt = false } = {}) { let questions = []; if (!skipPrompt) { let shouldPrompt = false; const missingProperties = []; const modelSchema = find(schema).schema; Object.keys(modelSchema.properties).forEach(prop => { const descriptor = modelSchema.properties[prop]; if (!object[prop]) { if (!shouldPrompt && modelSchema.required && modelSchema.required.includes(prop)) { shouldPrompt = true; } missingProperties.push({ name: prop, descriptor }); } }); if (shouldPrompt) { questions = missingProperties.map(p => { const required = modelSchema.required.includes(p.name) ? ' [required]' : ''; return { name: p.name, message: `Enter ${chalk.yellow(p.name)}${chalk.green(required)}:`, default: object[p.name] || p.descriptor.default, validate: input => !modelSchema.required.includes(p.name) || (!!input && modelSchema.required.includes(p.name)), filter: input => input === '' && !modelSchema.required.includes(p.name) ? undefined : input }; }); } } const validateData = data => { const { isValid, error } = validate(schema, data); if (!isValid) { this.log.error(error); if (!skipPrompt) { return this.prompt(questions).then(validateData); } throw new Error(error); } return data; }; return this.prompt(questions).then((answers) => { Object.assign(object, answers); return validateData(object); }); } };