From 30082f87262fa7428172fcbb6710b66d4bfe6261 Mon Sep 17 00:00:00 2001 From: Anselm Stordeur Date: Mon, 14 Jan 2019 16:45:07 +0100 Subject: [PATCH] fix: wait for config file validation --- src/app.ts | 224 +++++++++++++++++++++++++++-------------------------- 1 file changed, 116 insertions(+), 108 deletions(-) diff --git a/src/app.ts b/src/app.ts index cb093515..98e0b5a1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -36,123 +36,131 @@ import {Elasticsearch} from './storage/elasticsearch/Elasticsearch'; export const app = express(); -// only accept json as content type for all requests -app.use(bodyParser.json({ - limit: '500kb', - type: (req) => { - const contentType = typeof req.headers['Content-Type'] === 'string' ? - req.headers['Content-Type'] : req.headers['content-type']; - if (typeof contentType === 'string' && contentType.match(/^application\/json/)) { - return true; - } else { - throw new SCUnsupportedMediaTypeErrorResponse(process.env.NODE_ENV !== 'production'); - } - }, -})); // 500kb should be reasonably large +async function configureApp() { + // only accept json as content type for all requests + app.use(bodyParser.json({ + limit: '500kb', + type: (req) => { + const contentType = typeof req.headers['Content-Type'] === 'string' ? + req.headers['Content-Type'] : req.headers['content-type']; + if (typeof contentType === 'string' && contentType.match(/^application\/json/)) { + return true; + } else { + throw new SCUnsupportedMediaTypeErrorResponse(process.env.NODE_ENV !== 'production'); + } + }, + })); // 500kb should be reasonably large -// use morgan as a request logger -// request loggers have to be the first middleware to be set in express -app.use(morgan('dev')); + // use morgan as a request logger + // request loggers have to be the first middleware to be set in express + app.use(morgan('dev')); -const databases: {[name: string]: DatabaseConstructor} = { - elasticsearch: Elasticsearch, -}; + const databases: {[name: string]: DatabaseConstructor} = { + elasticsearch: Elasticsearch, + }; -// validate config file -export const scValidator = new Validator(); -scValidator.addSchemas(join('node_modules', '@openstapps', 'core', 'lib', 'schema')); + // validate config file + const scValidator = new Validator(); + await scValidator.addSchemas(join('node_modules', '@openstapps', 'core', 'lib', 'schema')); -// validate the config file -const configValidation = scValidator.validate(config.util.toObject(), 'SCConfigFile'); + // validate the config file + const configValidation = scValidator.validate(config.util.toObject(), 'SCConfigFile'); -// validation failed -if (configValidation.errors.length > 0) { - throw new Error( - 'Validation of config file failed. Errors were: ' + - JSON.stringify(configValidation.errors), - ); -} - -// check if a database name was given -if (!config.has('internal.database.name')) { - throw new Error('You have to configure a database'); -} - -if (typeof mailer !== 'undefined') { - // set a mailQueue to use the backend mailer - if (config.has('internal.monitoring')) { - app.set('mailQueue', new MailQueue(mailer)); + // validation failed + if (configValidation.errors.length > 0) { + throw new Error( + 'Validation of config file failed. Errors were: ' + + JSON.stringify(configValidation.errors), + ); } -} -const database = - new databases[config.get('internal.database.name')]( - config.util.toObject(), - app.get('mailQueue'), + // check if a database name was given + if (!config.has('internal.database.name')) { + throw new Error('You have to configure a database'); + } + + if (typeof mailer !== 'undefined') { + // set a mailQueue to use the backend mailer + if (config.has('internal.monitoring')) { + app.set('mailQueue', new MailQueue(mailer)); + } + } + + const database = + new databases[config.get('internal.database.name')]( + config.util.toObject(), + app.get('mailQueue'), + ); + + if (typeof database === 'undefined') { + throw new Error('No implementation for configured database found. Please check your configuration.'); + } + + logger.ok('Validated config file sucessfully'); + + // make the validator available on the app + app.set('validator', scValidator); + + // treats /foo and /foo/ as two different routes + // see http://expressjs.com/en/api.html#app.set + app.set('strict routing', true); + + // make the bulk storage available to all http middlewares/routes + app.set( + 'bulk', + new BulkStorage(database), ); -if (typeof database === 'undefined') { - throw new Error('No implementation for configured database found. Please check your configuration.'); + const corsOptions = { + allowedHeaders: [ + 'DNT', + 'Keep-Alive', + 'User-Agent', + 'X-Requested-With', + 'If-Modified-Since', + 'Cache-Control', + 'Content-Type', + 'X-StApps-Version', + ], + credentials: true, + maxAge: 1728000, + methods: ['GET', 'POST', 'PUT', 'OPTIONS'], + optionsSuccessStatus: 204, + }; + + // allow all origins on all routes + app.use(cors(corsOptions)); + // TODO: See if it can handle options request with no content-type + + // allow cors preflight requests on every route + app.options('*', cors(corsOptions)); + + app.set('isProductiveEnvironment', process.env.NODE_ENV !== 'production'); + + // load routes before plugins + // they now can be used or overwritten by any plugin + app.use( + bulkAddRouter, + bulkDoneRouter, + bulkRouter, + indexRouter, + multiSearchRouter, + searchRouter, + thingUpdateRouter, + ); + + // add a route for a missing resource (404) + app.use((_req, res) => { + const errorResponse = new SCNotFoundErrorResponse(process.env.NODE_ENV !== 'production'); + res.status(errorResponse.statusCode); + res.json(errorResponse); + }); + + // TODO: implement a route to register plugins } -logger.ok('Validated config file sucessfully'); - -// make the validator available on the app -app.set('validator', scValidator); - -// treats /foo and /foo/ as two different routes -// see http://expressjs.com/en/api.html#app.set -app.set('strict routing', true); - -// make the bulk storage available to all http middlewares/routes -app.set( - 'bulk', - new BulkStorage(database), -); - -const corsOptions = { - allowedHeaders: [ - 'DNT', - 'Keep-Alive', - 'User-Agent', - 'X-Requested-With', - 'If-Modified-Since', - 'Cache-Control', - 'Content-Type', - 'X-StApps-Version', - ], - credentials: true, - maxAge: 1728000, - methods: ['GET', 'POST', 'PUT', 'OPTIONS'], - optionsSuccessStatus: 204, -}; - -// allow all origins on all routes -app.use(cors(corsOptions)); -// TODO: See if it can handle options request with no content-type - -// allow cors preflight requests on every route -app.options('*', cors(corsOptions)); - -app.set('isProductiveEnvironment', process.env.NODE_ENV !== 'production'); - -// load routes before plugins -// they now can be used or overwritten by any plugin -app.use( - bulkAddRouter, - bulkDoneRouter, - bulkRouter, - indexRouter, - multiSearchRouter, - searchRouter, - thingUpdateRouter, -); - -// add a route for a missing resource (404) -app.use((_req, res) => { - const errorResponse = new SCNotFoundErrorResponse(process.env.NODE_ENV !== 'production'); - res.status(errorResponse.statusCode); - res.json(errorResponse); +configureApp().then(() => { + logger.ok('Sucessfully configured express server'); +}).catch((err) => { + throw err; }); - -// TODO: implement a route to register plugins