feat(core): Allow using middlewares with decorators on a per-route basis (no-changelog) (#5656)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-03-09 15:08:48 +01:00 committed by GitHub
parent 356e916194
commit d872866add
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 8 deletions

View file

@ -1,15 +1,25 @@
import type { RequestHandler } from 'express';
import { CONTROLLER_ROUTES } from './constants'; import { CONTROLLER_ROUTES } from './constants';
import type { Method, RouteMetadata } from './types'; import type { Method, RouteMetadata } from './types';
interface RouteOptions {
middlewares?: RequestHandler[];
}
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
const RouteFactory = const RouteFactory =
(method: Method) => (method: Method) =>
(path: `/${string}`): MethodDecorator => (path: `/${string}`, options: RouteOptions = {}): MethodDecorator =>
(target, handlerName) => { (target, handlerName) => {
const controllerClass = target.constructor; const controllerClass = target.constructor;
const routes = (Reflect.getMetadata(CONTROLLER_ROUTES, controllerClass) ?? const routes = (Reflect.getMetadata(CONTROLLER_ROUTES, controllerClass) ??
[]) as RouteMetadata[]; []) as RouteMetadata[];
routes.push({ method, path, handlerName: String(handlerName) }); routes.push({
method,
path,
middlewares: options.middlewares ?? [],
handlerName: String(handlerName),
});
Reflect.defineMetadata(CONTROLLER_ROUTES, routes, controllerClass); Reflect.defineMetadata(CONTROLLER_ROUTES, routes, controllerClass);
}; };

View file

@ -20,17 +20,18 @@ export const registerController = (app: Application, config: Config, controller:
const restBasePath = config.getEnv('endpoints.rest'); const restBasePath = config.getEnv('endpoints.rest');
const prefix = `/${[restBasePath, controllerBasePath].join('/')}`.replace(/\/+/g, '/'); const prefix = `/${[restBasePath, controllerBasePath].join('/')}`.replace(/\/+/g, '/');
const middlewares = ( const controllerMiddlewares = (
(Reflect.getMetadata(CONTROLLER_MIDDLEWARES, controllerClass) ?? []) as MiddlewareMetadata[] (Reflect.getMetadata(CONTROLLER_MIDDLEWARES, controllerClass) ?? []) as MiddlewareMetadata[]
).map( ).map(
({ handlerName }) => ({ handlerName }) =>
(controller as Controller)[handlerName].bind(controller) as RequestHandler, (controller as Controller)[handlerName].bind(controller) as RequestHandler,
); );
routes.forEach(({ method, path, handlerName }) => { routes.forEach(({ method, path, middlewares: routeMiddlewares, handlerName }) => {
router[method]( router[method](
path, path,
...middlewares, ...controllerMiddlewares,
...routeMiddlewares,
send(async (req: Request, res: Response) => send(async (req: Request, res: Response) =>
(controller as Controller)[handlerName](req, res), (controller as Controller)[handlerName](req, res),
), ),

View file

@ -1,4 +1,4 @@
import type { Request, Response } from 'express'; import type { Request, Response, RequestHandler } from 'express';
export type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'; export type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
@ -10,7 +10,10 @@ export interface RouteMetadata {
method: Method; method: Method;
path: string; path: string;
handlerName: string; handlerName: string;
middlewares: RequestHandler[];
} }
type RequestHandler = (req?: Request, res?: Response) => Promise<unknown>; export type Controller = Record<
export type Controller = Record<RouteMetadata['handlerName'], RequestHandler>; RouteMetadata['handlerName'],
(req?: Request, res?: Response) => Promise<unknown>
>;