UNPKG

10.4 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3require("reflect-metadata");
4const injection_js_1 = require("injection-js");
5const YAML = require("yamljs");
6const express = require("express");
7const logger = require("morgan");
8const bodyParser = require("body-parser");
9const cookieParser = require("cookie-parser");
10const http = require("http");
11const Promise = require("bluebird");
12const knex = require("knex");
13const objection_1 = require("objection");
14const lodash_1 = require("lodash");
15const winston = require("winston");
16const logger_1 = require("./logger");
17class ParkaApp {
18 constructor(ConfigConstructor) {
19 this.ConfigConstructor = ConfigConstructor;
20 this.configFile = process.env.PARKA_CONFIG_FILE;
21 process.nextTick(() => {
22 ParkaApp.appInstance = this;
23 this.parseAppConfig().then(() => {
24 this.configureDatabaseConneciton();
25 this.configureExpressServer();
26 lodash_1.forEach(this['__resourceClasses'], (ResourceClass) => {
27 this.registerResource(ResourceClass);
28 });
29 this.onBeforeApplicationStart();
30 this.configureGlobalErrorHandling();
31 this.configureInjector();
32 this.start();
33 });
34 });
35 }
36 onBeforeApplicationStart() {
37 }
38 registerResource(ResourceClass) {
39 this.registerGetRoutes(ResourceClass);
40 this.registerPostRoutes(ResourceClass);
41 this.registerPutRoutes(ResourceClass);
42 this.registerDeleteRoutes(ResourceClass);
43 }
44 registerDeleteRoutes(ResourceClass) {
45 let deleteMethods = ResourceClass.__delete;
46 if (typeof deleteMethods !== 'undefined') {
47 deleteMethods.forEach((deleteMethod) => {
48 this.expressApp.delete(this.getPath(ResourceClass, deleteMethod), (req, res) => {
49 let resource = new ResourceClass(...this.getDiArgs(ResourceClass));
50 resource.req = req;
51 resource.res = res;
52 let paramList = this.getParamList(ResourceClass, deleteMethod.methodName, req);
53 Promise.resolve(resource[deleteMethod.methodName].apply(resource, paramList)).then((returnValue) => {
54 res.json(returnValue);
55 }).catch((err) => res.status(err.statusCode || 500).json(err));
56 });
57 });
58 }
59 }
60 registerPutRoutes(ResourceClass) {
61 let putMethods = ResourceClass.__put;
62 if (typeof putMethods !== 'undefined') {
63 putMethods.forEach((putMethod) => {
64 this.expressApp.put(this.getPath(ResourceClass, putMethod), (req, res) => {
65 let resource = new ResourceClass(...this.getDiArgs(ResourceClass));
66 resource.req = req;
67 resource.res = res;
68 let paramList = this.getParamList(ResourceClass, putMethod.methodName, req);
69 Promise.resolve(resource[putMethod.methodName].apply(resource, paramList)).then((returnValue) => {
70 res.json(returnValue);
71 }).catch((err) => res.status(err.statusCode || 500).json(err));
72 });
73 });
74 }
75 }
76 registerPostRoutes(ResourceClass) {
77 let postMethods = ResourceClass.__post;
78 if (typeof postMethods !== 'undefined') {
79 postMethods.forEach((postMethod) => {
80 this.expressApp.post(this.getPath(ResourceClass, postMethod), (req, res) => {
81 let resource = new ResourceClass(...this.getDiArgs(ResourceClass));
82 resource.req = req;
83 resource.res = res;
84 let paramList = this.getParamList(ResourceClass, postMethod.methodName, req);
85 Promise.resolve(resource[postMethod.methodName].apply(resource, paramList)).then((returnValue) => {
86 res.json(returnValue);
87 }).catch((err) => res.status(err.statusCode || 500).json(err));
88 });
89 });
90 }
91 }
92 registerGetRoutes(ResourceClass) {
93 let getMethods = ResourceClass.__get;
94 if (typeof getMethods !== 'undefined') {
95 getMethods.forEach((getMethod) => {
96 this.expressApp.get(this.getPath(ResourceClass, getMethod), (req, res) => {
97 let resource = new ResourceClass(...this.getDiArgs(ResourceClass));
98 resource.req = req;
99 resource.res = res;
100 let paramList = this.getParamList(ResourceClass, getMethod.methodName, req);
101 Promise.resolve(resource[getMethod.methodName].apply(resource, paramList)).then((returnValue) => {
102 res.json(returnValue);
103 }).catch((err) => res.status(err.statusCode || 500).json(err));
104 });
105 });
106 }
107 }
108 getDiArgs(injectable) {
109 const paramTypes = Reflect.getMetadata('design:paramtypes', injectable);
110 return lodash_1.map(paramTypes, (param) => ParkaApp.appInstance['__injector'].get(param));
111 }
112 getParamList(ResourceClass, methodName, req) {
113 if (typeof ResourceClass.prototype[methodName].__params !== 'undefined') {
114 return ResourceClass.prototype[methodName].__params.map((paramDef) => {
115 if (paramDef.paramType === 'PATH_PARAM') {
116 return req.params[paramDef.paramName];
117 }
118 else if (paramDef.paramType === 'QUERY_PARAM') {
119 return req.query[paramDef.paramName];
120 }
121 else if (paramDef.paramType === 'REQUEST_BODY') {
122 let constructedModel = this.constructCorrectType(req, paramDef);
123 constructedModel.$validate();
124 return constructedModel;
125 }
126 });
127 }
128 else {
129 return [];
130 }
131 }
132 constructCorrectType(req, paramDef) {
133 if (typeof paramDef.constructor !== 'undefined') {
134 if (paramDef.isArray === true) {
135 return req.body.map((item) => {
136 return paramDef.constructor.fromJson(item);
137 });
138 }
139 else {
140 return paramDef.constructor.fromJson(req.body);
141 }
142 }
143 else {
144 return req.body;
145 }
146 }
147 getPath(ResourceClass, getMethod) {
148 let path = [];
149 if (this.config.routing && this.config.routing.prefix) {
150 path.push(this.config.routing.prefix);
151 }
152 path.push(ResourceClass.__path);
153 let methodPath = ResourceClass.prototype[getMethod.methodName].__path;
154 if (typeof methodPath !== 'undefined') {
155 path.push(methodPath);
156 }
157 return path.join('');
158 }
159 start() {
160 let server = http.createServer(this.expressApp);
161 server.listen(this.config.port, this.config.host, () => {
162 console.log('server listening at ', server.address().address + ':' + server.address().port);
163 });
164 }
165 parseAppConfig() {
166 let configFileContents = YAML.load(this.configFile);
167 this.config = new this.ConfigConstructor(configFileContents);
168 return Promise.resolve(this.config.configureApplication)
169 .then(() => {
170 this['__providers'].push({
171 provide: this.ConfigConstructor,
172 useValue: this.config
173 });
174 });
175 }
176 configureExpressServer() {
177 let app = express();
178 const winstonLogger = this.configureLogger();
179 this['__providers'].push({ provide: logger_1.Logger, useValue: winstonLogger });
180 app.use(logger('combined', { immediate: true, stream: { write: (message) => winstonLogger.info(message) } }));
181 app.use(bodyParser.json());
182 app.use(bodyParser.urlencoded({ extended: false }));
183 app.use(cookieParser());
184 app.get('/', (req, res) => {
185 res.send('it worked');
186 });
187 this.expressApp = app;
188 }
189 configureLogger() {
190 const logger = new winston.Logger({
191 exitOnError: false
192 });
193 if (this.config.logger && this.config.logger.transports) {
194 lodash_1.forEach(this.config.logger.transports, (options, transportName) => {
195 logger.add(winston.transports[transportName], options);
196 });
197 }
198 else {
199 logger.add(winston.transports.Console, {
200 level: 'debug',
201 handleExceptions: true,
202 json: false,
203 colorize: true,
204 timestamp: true
205 });
206 }
207 return logger;
208 }
209 configureInjector() {
210 this.__injector = injection_js_1.ReflectiveInjector.resolveAndCreate(this['__providers']);
211 }
212 configureGlobalErrorHandling() {
213 // Handle non matched routes
214 this.expressApp.use('*', (req, res, next) => {
215 res.status(404)
216 .json({
217 status: 404,
218 message: 'Not Found',
219 stacktrace: this.getStacktrace()
220 });
221 });
222 this.expressApp.use((err, req, res, next) => {
223 if (err) {
224 console.error(err.stack);
225 }
226 // if (err instanceof ValidationError === true) {
227 if (typeof err.statusCode === 'number' && typeof err.data !== 'undefined') {
228 res.status(err.statusCode).json(err);
229 }
230 else {
231 res.status(500)
232 .json({
233 status: 500,
234 message: err.message,
235 stacktrace: this.getStacktrace(err)
236 });
237 }
238 });
239 }
240 getStacktrace(err) {
241 if (typeof err !== 'undefined') {
242 return (this.config.includeStacktraceInResponse) ? err.stack : null;
243 }
244 else {
245 return (this.config.includeStacktraceInResponse) ? new Error().stack : null;
246 }
247 }
248 configureDatabaseConneciton() {
249 const conn = knex(this.config.db);
250 objection_1.Model.knex(conn);
251 }
252}
253exports.ParkaApp = ParkaApp;
254//# sourceMappingURL=parka-app.js.map
\No newline at end of file