@dechamp/express-auto-route
Version:
An express auto route module which allows routes and middleware to be configured via config file.
124 lines (101 loc) • 3.49 kB
text/typescript
import joi from "@hapi/joi";
import moduleImporter from "./moduleImporter";
import { RequestParamHandler } from "express";
export interface AutoRoutePropsConfigs {
routeBasePath?: string;
}
export interface AutoRouteProps {
server: any;
callbackHandler: any;
configs?: AutoRoutePropsConfigs;
}
export enum Methods {
GET = "GET",
POST = "POST",
HEAD = "HEAD",
PUT = "PUT",
DELETE = "DELETE",
USE = "USE",
}
export interface Route {
id: string;
method: Methods;
path: string;
modulePath: string;
requestJsonSchema?: {
body: string;
};
responseJsonSchema?: string;
middleware?: RequestParamHandler[];
}
class AutoRoute<AutoRouteProps> {
private readonly server: any;
private readonly callbackHandler: any;
private readonly configs?: AutoRoutePropsConfigs = {};
constructor(server, callbackHandler, configs) {
this.server = server;
this.callbackHandler = callbackHandler;
this.configs = configs;
}
async mount(routes: Route[]): Promise<string[]> {
this._guardParams(routes);
return Promise.all(routes.map(async route => this._addRoute(route)));
}
_guardParams(routes) {
joi.assert(
routes,
joi.array().items(
joi.object({
id: joi.string().required(),
method: joi.string()
.regex(/^GET|POST|HEAD|PUT|DELETE|USE$/)
.required(),
path: joi.string().min(1).required(),
modulePath: joi.string().min(1).required(),
}).unknown(true),
).required(),
);
}
async _addRoute(route) {
try {
const {method, path, middleware = []} = route;
const autoRouteCallback = await this._buildCallback(route);
if (middleware.length) {
const middlewareCallbacks: any[] = await this._buildMiddlewareCallbacks(middleware);
this.server[method.toLowerCase()](path, ...middlewareCallbacks, ...autoRouteCallback);
} else {
this.server[method.toLowerCase()](path, ...autoRouteCallback);
}
return `${route.id}: mounted`;
} catch (error) {
return `${route.id} did not mount due to ${error.message}`;
}
}
async _buildCallback(route) {
let callbacks: ((req: any, res: any, next: any) => any)[] = [];
if (this.callbackHandler) {
callbacks = this.callbackHandler.buildCallback(route);
}
const {modulePath} = route;
const callbackModule = await this._buildMiddlewareCallback(modulePath);
if (callbackModule) {
const callback = (req, res, next) => {
req.config = {
route,
};
callbackModule(req, res, next);
};
callbacks.push(callback);
}
return callbacks;
}
async _buildMiddlewareCallbacks(middlewares: string[]): Promise<any[]> {
return Promise.all(middlewares.map(async middleware => this._buildMiddlewareCallback(middleware)));
}
async _buildMiddlewareCallback(middlewarePath: string): Promise<(req: any, res: any, next: () => any) => any> {
return moduleImporter(middlewarePath, (this.configs && this.configs.routeBasePath));
}
}
export {
AutoRoute
};