UNPKG

10.3 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const express = require("express");
4const bodyParser = require("body-parser");
5const cookieParser = require("cookie-parser");
6const lodash_1 = require("lodash");
7const APIConfig_1 = require("./lib/APIConfig");
8exports.APIConfig = APIConfig_1.APIConfig;
9const path = require("path");
10const APIUtils_1 = require("./lib/APIUtils");
11exports.APIUtils = APIUtils_1.APIUtils;
12require("reflect-metadata");
13const APIResponse_1 = require("./lib/APIResponse");
14exports.APIResponse = APIResponse_1.APIResponse;
15const APIError_1 = require("./lib/APIError");
16exports.APIError = APIError_1.APIError;
17const KVService_1 = require("./lib/Services/KeyValue/KVService");
18exports.APIKVService = KVService_1.KVService;
19const FileService_1 = require("./lib/Services/File/FileService");
20exports.APIFileService = FileService_1.FileService;
21const Config_1 = require("./lib/Services/Config");
22exports.EnvVarSync = Config_1.EnvVarSync;
23function _createHandlerWrapperFunction(handlerData, thisObject) {
24 return (req, res, next) => {
25 let apiResponse = new APIResponse_1.APIResponse(req, res, next);
26 let handlerArgs = [];
27 let validationErrors = [];
28 // Loop through each parameter in our function and pull it from the request
29 for (let index = 0; index < handlerData.handlerParameterNames.length; index++) {
30 let paramData = handlerData.handlerParameterData[index];
31 let paramOptions = lodash_1.get(paramData, "paramOptions", {});
32 let paramName = APIUtils_1.APIUtils.coalesce(paramOptions.rawName, handlerData.handlerParameterNames[index]);
33 // Ignore request and response parameters if the function asks for it
34 if ((index === handlerData.handlerParameterNames.length - 1 || index === handlerData.handlerParameterNames.length - 2) && ["req", "request", "res", "response"].indexOf(paramName.toLowerCase()) >= 0) {
35 continue;
36 }
37 let paramSources = lodash_1.castArray(lodash_1.get(paramOptions, "sources", ["params", "query", "body", "cookie", "headers"]));
38 let paramValue;
39 for (let paramSource of paramSources) {
40 let paramValues = lodash_1.get(req, paramSource);
41 if (lodash_1.isNil(paramValues)) {
42 continue;
43 }
44 if (paramOptions.includeFullSource ||
45 (/[\.\[\]]/g).test(paramSource) // If the source contains any of the characters ".[]" (ie a path), assume the developer meant to include the full source.
46 ) {
47 paramValue = paramValues;
48 break;
49 }
50 else {
51 if (lodash_1.has(paramValues, paramName)) {
52 paramValue = paramValues[paramName];
53 break;
54 }
55 }
56 }
57 let argValue = APIUtils_1.APIUtils.coalesce(paramValue, paramOptions.defaultValue);
58 if (paramOptions.processor) {
59 try {
60 argValue = paramOptions.processor(argValue, req);
61 }
62 catch (error) {
63 validationErrors.push({
64 parameter: paramName,
65 message: error.message || error.toString()
66 });
67 continue;
68 }
69 }
70 if (lodash_1.isNil(argValue)) {
71 // Is this parameter required?
72 if (!lodash_1.get(paramOptions, "optional", false)) {
73 validationErrors.push({
74 parameter: paramName,
75 message: "missing"
76 });
77 }
78 handlerArgs.push(undefined);
79 continue;
80 }
81 argValue = APIUtils_1.APIUtils.convertToType(argValue, paramData.paramType);
82 if (lodash_1.isNil(argValue) || lodash_1.isNaN(argValue)) {
83 validationErrors.push({
84 parameter: paramName,
85 message: "invalid"
86 });
87 continue;
88 }
89 handlerArgs.push(argValue);
90 }
91 if (validationErrors.length > 0) {
92 apiResponse.withError(APIError_1.APIError.createValidationError(validationErrors));
93 return;
94 }
95 apiResponse.processHandlerFunction(thisObject, handlerData.handlerFunction, handlerArgs, handlerData.options.successResponse);
96 };
97}
98function _loadAPI(apiRouter, apiDefinition) {
99 let apiModule;
100 try {
101 apiModule = require(path.resolve(process.cwd(), apiDefinition.require));
102 }
103 catch (e) {
104 console.error(e);
105 return null;
106 }
107 if (lodash_1.isNil(apiModule)) {
108 return null;
109 }
110 let moduleName = APIUtils_1.APIUtils.coalesce(apiDefinition.moduleName, path.basename(apiDefinition.require));
111 let apiClass = APIUtils_1.APIUtils.coalesce(apiModule[moduleName], apiModule.default, apiModule);
112 let apiInstance;
113 lodash_1.each(lodash_1.get(apiClass, "__handlerData", {}), (handlerData, name) => {
114 // If this is an instance function, we need to create an instance of the class
115 if (handlerData.isInstance && lodash_1.isNil(apiInstance)) {
116 apiInstance = new apiClass();
117 }
118 let options = handlerData.options;
119 let argsArray = [options.path];
120 if (options.middleware) {
121 argsArray = argsArray.concat(lodash_1.castArray(options.middleware));
122 }
123 let handlerWrapper = _createHandlerWrapperFunction(handlerData, handlerData.isInstance ? apiInstance : apiClass);
124 argsArray.push(handlerWrapper);
125 apiRouter[options.method.toLowerCase()].apply(apiRouter, argsArray);
126 });
127}
128class APILove {
129 static start(options) {
130 if (options.loadStandardMiddleware !== false) {
131 this.app.use(cookieParser());
132 this.app.use(bodyParser.json());
133 this.app.use(bodyParser.urlencoded({ extended: false }));
134 this.app.use(bodyParser.text());
135 }
136 for (let mw of lodash_1.get(options, "middleware", [])) {
137 this.app.use(mw);
138 }
139 // Here we load our APIs, but we only load them when requested
140 for (let api of lodash_1.get(options, "apis", [])) {
141 if (lodash_1.isNil(api.apiPath)) {
142 api.apiPath = "";
143 }
144 if (APIConfig_1.APIConfig.LAZY_LOAD_APIS) {
145 let apiRouter;
146 this.app.use(api.apiPath, (req, res, next) => {
147 // Lazy load our API
148 if (!apiRouter) {
149 apiRouter = express.Router();
150 _loadAPI(apiRouter, api);
151 }
152 apiRouter(req, res, next);
153 });
154 }
155 else {
156 let apiRouter = express.Router();
157 _loadAPI(apiRouter, api);
158 this.app.use(api.apiPath, apiRouter);
159 }
160 }
161 if (!lodash_1.isNil(options.defaultRouteHandler)) {
162 this.app.use(options.defaultRouteHandler);
163 }
164 // Setup our default error handler
165 if (!lodash_1.isNil(options.defaultErrorHandler)) {
166 this.app.use(options.defaultErrorHandler);
167 }
168 else {
169 this.app.use((error, req, res, next) => {
170 if (error instanceof APIError_1.APIError) {
171 let apiError = error;
172 res.status(apiError.statusCode).send(APIConfig_1.APIConfig.OUTPUT_HAPI_RESULTS ? apiError.hapiOut() : apiError.out());
173 }
174 else {
175 let apiResponse = new APIResponse_1.APIResponse(res, res);
176 apiResponse.withError(error);
177 }
178 });
179 }
180 if (APIConfig_1.APIConfig.RUN_AS_SERVER) {
181 this.app.listen(APIConfig_1.APIConfig.WEB_PORT, () => console.log(`API listening on port ${APIConfig_1.APIConfig.WEB_PORT}`));
182 return this.app;
183 }
184 else {
185 let serverless = require("serverless-http");
186 return serverless(this.app, { callbackWaitsForEmptyEventLoop: true });
187 }
188 }
189}
190APILove.app = express();
191exports.APILove = APILove;
192function APIParameter(options) {
193 return function (target, key, parameterIndex) {
194 let isInstance = lodash_1.isNil(target.prototype);
195 let theClass = isInstance ? target.constructor : target.prototype.constructor;
196 let handlerData = lodash_1.get(theClass, `__handlerData.${key}`, {});
197 lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramOptions`, options);
198 lodash_1.set(theClass, `__handlerData.${key}`, handlerData);
199 };
200}
201exports.APIParameter = APIParameter;
202function APIEndpoint(options) {
203 return function (target, key, descriptor) {
204 let isInstance = lodash_1.isNil(target.prototype);
205 let theClass = isInstance ? target.constructor : target.prototype.constructor;
206 let handlerData = lodash_1.get(theClass, `__handlerData.${key}`, {});
207 options = lodash_1.defaultsDeep({}, options, {
208 method: "get",
209 path: "/"
210 });
211 let parameterMetadata = Reflect.getMetadata("design:paramtypes", target, key);
212 let parameterNames = APIUtils_1.APIUtils.getFunctionParamNames(descriptor.value);
213 handlerData.isInstance = isInstance;
214 handlerData.handlerFunction = descriptor.value;
215 handlerData.options = options;
216 handlerData.handlerParameterNames = parameterNames;
217 for (let parameterIndex = 0; parameterIndex < parameterNames.length; parameterIndex++) {
218 lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramType`, APIUtils_1.APIUtils.getRawTypeName(parameterMetadata[parameterIndex].prototype));
219 lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramName`, parameterNames[parameterIndex]);
220 }
221 lodash_1.set(theClass, `__handlerData.${key}`, handlerData);
222 };
223}
224exports.APIEndpoint = APIEndpoint;
225//# sourceMappingURL=APILove.js.map
\No newline at end of file