UNPKG

hors

Version:
135 lines (134 loc) 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const inversify_1 = require("inversify"); const express = require("express"); const uuid = require("uuid"); require("reflect-metadata"); const metadata = require("./metadata"); const simple_event_1 = require("./simple-event"); const transaction_1 = require("./transaction/transaction"); const transaction_utils_1 = require("./transaction/transaction-utils"); class HorsServer { constructor() { this.iocContainer = new inversify_1.Container(); this.app = express(); this.httpServerInstance = null; this.authenticationMiddleware = null; this.errorHandler = (transaction) => transaction.send.internalServerError(); this.notFoundHandler = (transaction) => transaction.send.notFound(); this.expressConfigurationHandler = null; // Hooks this.onTransactionStart = new simple_event_1.SimpleEvent(); this.onTransactionEnd = new simple_event_1.SimpleEvent(); this.onListen = new simple_event_1.SimpleEvent(); this.onRegisterEndpoint = new simple_event_1.SimpleEvent(); } start(port) { // Run express configuration handler if any. This has to be done here so // iocContainer is configured and ready for use if (typeof this.expressConfigurationHandler === 'function') { this.expressConfigurationHandler(this.app, this.iocContainer); } // Register middleware to add transaction into request object this.app.use(this.createAddTransactionMiddleware()); // Register own endpoints this.registerEndpoints(); // Trigger a onListen hook when server starts listening the given port return new Promise(resolve => { this.httpServerInstance = this.app.listen(port, () => { this.onListen.fire(port); resolve(); }); }); } stop() { return new Promise(resolve => { if (!this.httpServerInstance) { return resolve(); } this.httpServerInstance.close(() => resolve()); }); } setAuthenticationMiddleware(middleware) { this.authenticationMiddleware = middleware; return this; } setErrorHandler(handler) { this.errorHandler = handler; return this; } setNotFoundHandler(handler) { this.notFoundHandler = handler; return this; } configureIocContainer(handler) { handler(this.iocContainer); return this; } configureExpressInstance(handler) { this.expressConfigurationHandler = handler; return this; } getExpressInstance() { return this.app; } /** * Hydrates the Express application with endpoints and authentication middleware */ registerEndpoints() { const prefixUrl = (url) => (url.charAt(0) === '/') ? url : `/${url}`; // Convert auth middleware into express middlewares const authExpressMiddleware = (this.authenticationMiddleware) ? transaction_utils_1.createExpressMiddleware(this.authenticationMiddleware, this.iocContainer) : null; // Get endpoints from the Reflect metadata const endpoints = Reflect.getMetadata(metadata.ENDPOINTS_METADATA_SYMBOL, Reflect) || []; endpoints.forEach(endpoint => { // Extract needed information from the endpoint object const { method, public: isPublic, target, middleware } = endpoint; const url = prefixUrl(endpoint.url); // Convert endpoint middlewares into express middlewares const expressMiddleware = middleware.map(middleware => transaction_utils_1.createExpressMiddleware(middleware, this.iocContainer)); // Add authentication middleware into beginning of the middleware array // if endpoint needs a auhenticaiton if (!isPublic && authExpressMiddleware) { expressMiddleware.unshift(authExpressMiddleware); } // Trigger a onRegisterEndpoint hook this.onRegisterEndpoint.fire({ url, method, isPublic }); // Register endpoint to Express app this.app[method](url, expressMiddleware, (req, res, next) => { // Set target into iocContainer and retrieve it immediatly, // by doing this we have now instance with dependencies injected // by inversify this.iocContainer.bind(target).toSelf(); const instance = this.iocContainer.get(target); const handler = instance.handle.bind(instance); this.iocContainer.unbind(target); transaction_utils_1.createExpressHandler(handler)(req, res, next); }); }); // Register not found and error handlers this.notFoundHandler && this.app.use(transaction_utils_1.createExpressHandler(this.notFoundHandler)); this.errorHandler && this.app.use(transaction_utils_1.createExpressErrorHandler(this.errorHandler, this.iocContainer)); } /** * Creates a middleware for constracting the Transaction and injecting it into express request */ createAddTransactionMiddleware() { return (request, response, next) => { const correlationId = uuid.v4(); const transaction = new transaction_1.default(request, response, correlationId, () => this.onTransactionEnd.fire(transaction)); // Trigger a onTransactionStart -hook this.onTransactionStart.fire(transaction); // Set transaction into request request.transaction = transaction; next(); }; } } exports.HorsServer = HorsServer;