UNPKG

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