expresser
Version:
A ready to use Node.js web app wrapper, built on top of Express.
192 lines (191 loc) • 7.56 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Routes = void 0;
const app_1 = __importDefault(require("./app"));
const fs = require("fs");
const jaul = require("jaul");
const logger = require("anyhow");
const settings = require("setmeup").settings;
class Routes {
static _instance;
static get Instance() {
return this._instance || (this._instance = new this());
}
load = (options) => {
let specs;
if (!options || !options.handlers) {
throw new Error(`Missing options.handlers with the routing functions`);
}
logger.debug("Routes.load", options.filename, Object.keys(options.handlers));
if (options.specs) {
specs = options.specs;
}
else {
if (options.filename == null || options.filename == "") {
options.filename = settings.routes.filename;
}
try {
const filename = jaul.io.getFilePath(options.filename);
if (filename == null || !fs.existsSync(filename)) {
throw new Error(`File ${options.filename} not found.`);
}
specs = fs.readFileSync(filename, { encoding: settings.general.encoding }).toString();
specs = JSON.parse(specs);
}
catch (ex) {
logger.error("Routes.load", options.filename, ex);
throw ex;
}
}
for (let [route, spec] of Object.entries(specs)) {
if (typeof spec == "string") {
spec = { get: spec };
}
for (let [method, handlerKey] of Object.entries(spec)) {
const handler = options.handlers[handlerKey];
if (app_1.default[method] == null) {
logger.error("Routes.load", options.filename, route, `Invalid method: ${method}`);
throw new Error(`Invalid method: ${method}`);
}
else if (handler == null) {
logger.error("Routes.load", options.filename, route, `Invalid handler: ${handlerKey}`);
throw new Error(`Invalid handler: ${handlerKey}`);
}
else {
app_1.default[method](route, handler);
logger.info("Routes.load", options.filename, route, method, handlerKey);
}
}
}
};
loadSwagger = (options) => {
let specs;
if (!options || !options.handlers) {
throw new Error(`Missing options.handlers with the routing functions`);
}
logger.debug("Routes.loadSwagger", options.filename, Object.keys(options.handlers));
if (options.specs) {
specs = options.specs;
}
else {
if (options.filename == null || options.filename == "") {
options.filename = settings.routes.swagger.filename;
}
try {
const filename = jaul.io.getFilePath(options.filename);
if (filename == null || !fs.existsSync(filename)) {
throw new Error(`File ${options.filename} not found.`);
}
specs = fs.readFileSync(filename, { encoding: settings.general.encoding }).toString();
specs = JSON.parse(specs);
}
catch (ex) {
logger.error("Routes.loadSwagger", options.filename, ex);
throw ex;
}
}
if (options.version != null) {
specs.info.version = options.version;
}
for (let [path, pathSpec] of Object.entries(specs.paths)) {
path = path.toString().replace(/\/{/g, "/:");
path = path.replace(/\}/g, "");
for (let [method, methodSpec] of Object.entries(pathSpec)) {
if (methodSpec == null) {
throw new Error(`Missing method spec for ${method} ${path}`);
}
if (options.handlers[methodSpec.operationId] == null) {
throw new Error(`Missing route handler for ${methodSpec.operationId}`);
}
if (methodSpec.parameters == null) {
methodSpec.parameters = [];
}
logger.info("Routes.loadSwagger", options.filename, method, path, methodSpec.operationId);
app_1.default[method](path, (req, res, next) => {
try {
if (!req.swagger) {
req.swagger = {};
}
for (let parameterSpec of methodSpec.parameters) {
this.castParameter(req, parameterSpec);
}
options.handlers[methodSpec.operationId](req, res, next);
}
catch (ex) {
logger.error("Routes", method, path, methodSpec.operationId, ex);
}
});
}
}
if (settings.routes.swagger.exposeJson) {
app_1.default.get("/swagger.json", (_req, res) => res.json(specs));
}
};
castParameter = function (req, spec) {
try {
const { name } = spec;
let scope, separator;
switch (spec.in) {
case "query":
scope = "query";
break;
case "header":
scope = "header";
break;
case "path":
scope = "params";
break;
}
if (scope == null) {
return;
}
req.swagger[scope] = req.swagger[scope] || {};
const param = req[scope][name];
if (param == null) {
return;
}
if (spec.type == "string") {
if (spec.format == "date" || spec.format == "datetime" || spec.format == "date-time") {
req.swagger[scope][name] = new Date(param);
}
else {
req.swagger[scope][name] = param;
}
}
else if (spec.type == "number") {
req.swagger[scope][name] = parseFloat(param);
}
else if (spec.type == "integer") {
req.swagger[scope][name] = parseInt(param);
}
else if (spec.type == "boolean") {
req.swagger[scope][name] = param;
}
else if (spec.type == "array") {
switch (spec.collectionFormat) {
case "csv":
separator = ",";
break;
case "ssv":
separator = " ";
break;
case "pipes":
separator = "|";
break;
}
if (separator == null) {
return;
}
req.swagger[scope][name] = param.split(separator);
}
}
catch (ex) {
logger.error("Routes.castParameter", spec, ex);
}
};
}
exports.Routes = Routes;
exports.default = Routes.Instance;