1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.Routes = void 0;
|
7 | const app_1 = __importDefault(require("./app"));
|
8 | const _ = require("lodash");
|
9 | const fs = require("fs");
|
10 | const jaul = require("jaul");
|
11 | const logger = require("anyhow");
|
12 | const settings = require("setmeup").settings;
|
13 | class Routes {
|
14 | constructor() {
|
15 | this.load = (options) => {
|
16 | let specs;
|
17 | if (!options || !options.handlers) {
|
18 | throw new Error(`Missing options.handlers with the routing functions`);
|
19 | }
|
20 | logger.debug("Routes.load", options.filename, Object.keys(options.handlers));
|
21 | if (options.specs) {
|
22 | specs = options.specs;
|
23 | }
|
24 | else {
|
25 | if (options.filename == null || options.filename == "") {
|
26 | options.filename = settings.routes.filename;
|
27 | }
|
28 | try {
|
29 | const filename = jaul.io.getFilePath(options.filename);
|
30 | if (filename == null || !fs.existsSync(filename)) {
|
31 | throw new Error(`File ${options.filename} not found.`);
|
32 | }
|
33 | specs = fs.readFileSync(filename, { encoding: settings.general.encoding }).toString();
|
34 | specs = JSON.parse(specs);
|
35 | }
|
36 | catch (ex) {
|
37 | logger.error("Routes.load", options.filename, ex);
|
38 | throw ex;
|
39 | }
|
40 | }
|
41 | for (let [route, spec] of Object.entries(specs)) {
|
42 | if (_.isString(spec)) {
|
43 | spec = { get: spec };
|
44 | }
|
45 | for (let [method, handlerKey] of Object.entries(spec)) {
|
46 | const handler = options.handlers[handlerKey];
|
47 | if (app_1.default[method] == null) {
|
48 | logger.error("Routes.load", options.filename, route, `Invalid method: ${method}`);
|
49 | throw new Error(`Invalid method: ${method}`);
|
50 | }
|
51 | else if (handler == null) {
|
52 | logger.error("Routes.load", options.filename, route, `Invalid handler: ${handlerKey}`);
|
53 | throw new Error(`Invalid handler: ${handlerKey}`);
|
54 | }
|
55 | else {
|
56 | app_1.default[method](route, handler);
|
57 | logger.info("Routes.load", options.filename, route, method, handlerKey);
|
58 | }
|
59 | }
|
60 | }
|
61 | };
|
62 | this.loadSwagger = (options) => {
|
63 | let specs;
|
64 | if (!options || !options.handlers) {
|
65 | throw new Error(`Missing options.handlers with the routing functions`);
|
66 | }
|
67 | logger.debug("Routes.loadSwagger", options.filename, Object.keys(options.handlers));
|
68 | if (options.specs) {
|
69 | specs = options.specs;
|
70 | }
|
71 | else {
|
72 | if (options.filename == null || options.filename == "") {
|
73 | options.filename = settings.routes.swagger.filename;
|
74 | }
|
75 | try {
|
76 | const filename = jaul.io.getFilePath(options.filename);
|
77 | if (filename == null || !fs.existsSync(filename)) {
|
78 | throw new Error(`File ${options.filename} not found.`);
|
79 | }
|
80 | specs = fs.readFileSync(filename, { encoding: settings.general.encoding }).toString();
|
81 | specs = JSON.parse(specs);
|
82 | }
|
83 | catch (ex) {
|
84 | logger.error("Routes.loadSwagger", options.filename, ex);
|
85 | throw ex;
|
86 | }
|
87 | }
|
88 | if (options.version != null) {
|
89 | specs.info.version = options.version;
|
90 | }
|
91 | for (let [path, pathSpec] of Object.entries(specs.paths)) {
|
92 | path = path.toString().replace(/\/{/g, "/:");
|
93 | path = path.replace(/\}/g, "");
|
94 | for (let [method, methodSpec] of Object.entries(pathSpec)) {
|
95 | if (methodSpec == null) {
|
96 | throw new Error(`Missing method spec for ${method} ${path}`);
|
97 | }
|
98 | if (options.handlers[methodSpec.operationId] == null) {
|
99 | throw new Error(`Missing route handler for ${methodSpec.operationId}`);
|
100 | }
|
101 | if (methodSpec.parameters == null) {
|
102 | methodSpec.parameters = [];
|
103 | }
|
104 | logger.info("Routes.loadSwagger", options.filename, method, path, methodSpec.operationId);
|
105 | app_1.default[method](path, (req, res, next) => {
|
106 | try {
|
107 | if (!req.swagger) {
|
108 | req.swagger = {};
|
109 | }
|
110 | for (let parameterSpec of methodSpec.parameters) {
|
111 | this.castParameter(req, parameterSpec);
|
112 | }
|
113 | options.handlers[methodSpec.operationId](req, res, next);
|
114 | }
|
115 | catch (ex) {
|
116 | logger.error("Routes", method, path, methodSpec.operationId, ex);
|
117 | }
|
118 | });
|
119 | }
|
120 | }
|
121 | if (settings.routes.swagger.exposeJson) {
|
122 | app_1.default.get("/swagger.json", (_req, res) => res.json(specs));
|
123 | }
|
124 | };
|
125 | this.castParameter = function (req, spec) {
|
126 | try {
|
127 | const { name } = spec;
|
128 | let scope, separator;
|
129 | switch (spec.in) {
|
130 | case "query":
|
131 | scope = "query";
|
132 | break;
|
133 | case "header":
|
134 | scope = "header";
|
135 | break;
|
136 | case "path":
|
137 | scope = "params";
|
138 | break;
|
139 | }
|
140 | if (scope == null) {
|
141 | return;
|
142 | }
|
143 | req.swagger[scope] = req.swagger[scope] || {};
|
144 | const param = req[scope][name];
|
145 | if (param == null) {
|
146 | return;
|
147 | }
|
148 | if (spec.type == "string") {
|
149 | if (spec.format == "date" || spec.format == "datetime" || spec.format == "date-time") {
|
150 | req.swagger[scope][name] = new Date(param);
|
151 | }
|
152 | else {
|
153 | req.swagger[scope][name] = param;
|
154 | }
|
155 | }
|
156 | else if (spec.type == "number") {
|
157 | req.swagger[scope][name] = parseFloat(param);
|
158 | }
|
159 | else if (spec.type == "integer") {
|
160 | req.swagger[scope][name] = parseInt(param);
|
161 | }
|
162 | else if (spec.type == "boolean") {
|
163 | req.swagger[scope][name] = param;
|
164 | }
|
165 | else if (spec.type == "array") {
|
166 | switch (spec.collectionFormat) {
|
167 | case "csv":
|
168 | separator = ",";
|
169 | break;
|
170 | case "ssv":
|
171 | separator = " ";
|
172 | break;
|
173 | case "pipes":
|
174 | separator = "|";
|
175 | break;
|
176 | }
|
177 | if (separator == null) {
|
178 | return;
|
179 | }
|
180 | req.swagger[scope][name] = param.split(separator);
|
181 | }
|
182 | }
|
183 | catch (ex) {
|
184 | logger.error("Routes.castParameter", spec, ex);
|
185 | }
|
186 | };
|
187 | }
|
188 | static get Instance() {
|
189 | return this._instance || (this._instance = new this());
|
190 | }
|
191 | }
|
192 | exports.Routes = Routes;
|
193 | exports.default = Routes.Instance;
|