1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const express = require("express");
|
4 | const bodyParser = require("body-parser");
|
5 | const cookieParser = require("cookie-parser");
|
6 | const lodash_1 = require("lodash");
|
7 | const APIConfig_1 = require("./lib/APIConfig");
|
8 | exports.APIConfig = APIConfig_1.APIConfig;
|
9 | const path = require("path");
|
10 | const APIUtils_1 = require("./lib/APIUtils");
|
11 | exports.APIUtils = APIUtils_1.APIUtils;
|
12 | require("reflect-metadata");
|
13 | const APIResponse_1 = require("./lib/APIResponse");
|
14 | exports.APIResponse = APIResponse_1.APIResponse;
|
15 | const APIError_1 = require("./lib/APIError");
|
16 | exports.APIError = APIError_1.APIError;
|
17 | const KVService_1 = require("./lib/Services/KeyValue/KVService");
|
18 | exports.APIKVService = KVService_1.KVService;
|
19 | const FileService_1 = require("./lib/Services/File/FileService");
|
20 | exports.APIFileService = FileService_1.FileService;
|
21 | const Config_1 = require("./lib/Services/Config");
|
22 | exports.EnvVarSync = Config_1.EnvVarSync;
|
23 | function _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 |
|
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 |
|
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)
|
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 |
|
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 | }
|
98 | function _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 |
|
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 | }
|
128 | class 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 |
|
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 |
|
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 |
|
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 | }
|
190 | APILove.app = express();
|
191 | exports.APILove = APILove;
|
192 | function 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 | }
|
201 | exports.APIParameter = APIParameter;
|
202 | function 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 | }
|
224 | exports.APIEndpoint = APIEndpoint;
|
225 |
|
\ | No newline at end of file |