@tunframework/tun-rest-router
Version:
rest router for tun
171 lines (170 loc) • 6.34 kB
JavaScript
;
// @ts-check
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadRestifyRoutes = exports.RestifyRouter = void 0;
const tun_1 = require("@tunframework/tun");
const route_utils_js_1 = require("./route-utils.js");
class RestifyRouter {
_routes = [];
// temp prefix, consumed in addRoute()
_prefix = '';
_methods;
constructor({ prefix = '', methods } = {}) {
this.prefix(prefix);
this._methods = methods;
}
prefix(_prefix) {
this._prefix = _prefix || '';
return this;
}
routes() {
return (ctx, next) => {
let route = (0, route_utils_js_1.matchRoute)(ctx.req.method, ctx.req.path, this._routes);
if (!route) {
return next();
}
ctx.state.matchedRoute = route;
if (ctx.res.status === 404) {
ctx.res.status = 200;
}
let slugs = route.slugNames.reduce((p, n, nIndex) => {
p[n] = route.slugValues[nIndex];
return p;
}, {});
ctx.req.slugs = slugs;
return route.handler.call(null, ctx, next);
};
}
addRoute(methods, pathname, handler) {
this._routes.push({
// ...pathToRegexp(pathname),
...(0, route_utils_js_1.pathToRegexp)((this._prefix || '') + pathname),
methods: Array.isArray(methods) ? methods : [methods],
slugValues: [],
handler
});
return this;
}
get(pathname, handler) {
return this.addRoute('GET', pathname, handler);
}
head(pathname, handler) {
return this.addRoute('HEAD', pathname, handler);
}
post(pathname, handler) {
return this.addRoute('POST', pathname, handler);
}
put(pathname, handler) {
return this.addRoute('PUT', pathname, handler);
}
delete(pathname, handler) {
return this.addRoute('DELETE', pathname, handler);
}
// connect(pathname: string, handler: TunComposable<TunContext>) {
// return this.addRoute('CONNECT', pathname, handler);
// }
options(pathname, handler) {
return this.addRoute('OPTIONS', pathname, handler);
}
// trace(pathname: string, handler: TunComposable<TunContext>) {
// return this.addRoute('TRACE', pathname, handler);
// }
patch(pathname, handler) {
return this.addRoute('PATCH', pathname, handler);
}
/**
* Fufill response header if all middleware resolved and `ctx.status` is empty or 404(not_found).
*/
allowedMethods(options = {}) {
const implemented = this._methods || Object.keys(tun_1.HttpMethod);
return async function allowedMethods(ctx, next) {
await next();
if (ctx.res.status || ctx.res.status !== 404) {
return;
}
const allowed = {};
const matchedRoute = ctx.state.matchedRoute;
if (matchedRoute) {
matchedRoute.methods.forEach((method) => {
allowed[method] = method;
});
}
const allowedArr = Object.keys(allowed);
if (implemented.indexOf(ctx.req.method) > -1) {
if (options.throw) {
let throwable = null;
if (typeof options.notImplemented === 'function') {
throwable = options.notImplemented();
}
else {
throwable = new tun_1.HttpError({ status: 501 });
}
throw throwable;
}
else {
ctx.res.status = 501;
ctx.res.set('Allow', allowedArr);
}
}
else if (allowedArr.length) {
if (ctx.req.method === 'OPTIONS') {
ctx.res.status = 200;
ctx.body = '';
ctx.res.set('Allow', allowedArr);
}
else if (!allowed[ctx.req.method]) {
if (options.throw) {
let throwable = null;
if (typeof options.notImplemented === 'function') {
throwable = options.notImplemented();
}
else {
throwable = new tun_1.HttpError({ status: 405 });
}
throw throwable;
}
else {
ctx.res.status = 405;
ctx.res.set('Allow', allowedArr);
}
}
}
};
}
}
exports.RestifyRouter = RestifyRouter;
let loadRestifyRoutes = async (pathname) => {
let M = await Promise.resolve().then(() => __importStar(require(pathname)));
let list = Object.keys(M)
.filter((k) => M[k] instanceof RestifyRouter)
.map((k) => M[k]);
if (list.length === 1) {
return list[0];
}
// compose
let r = new RestifyRouter();
for (const item of list) {
r._routes.push(...item._routes);
}
return r;
};
exports.loadRestifyRoutes = loadRestifyRoutes;