diff --git a/packages/http/libraries/core/src/error/models/InversifyHttpAdapterErrorKind.ts b/packages/http/libraries/core/src/error/models/InversifyHttpAdapterErrorKind.ts index d4c54d33b..b4c992cab 100644 --- a/packages/http/libraries/core/src/error/models/InversifyHttpAdapterErrorKind.ts +++ b/packages/http/libraries/core/src/error/models/InversifyHttpAdapterErrorKind.ts @@ -1,4 +1,5 @@ export enum InversifyHttpAdapterErrorKind { + invalidOperationAfterBuild, noControllerFound, pipeError, requestParamIncorrectUse, diff --git a/packages/http/libraries/core/src/http/adapter/InversifyHttpAdapter.ts b/packages/http/libraries/core/src/http/adapter/InversifyHttpAdapter.ts index 0646e5207..5cf6a30e1 100644 --- a/packages/http/libraries/core/src/http/adapter/InversifyHttpAdapter.ts +++ b/packages/http/libraries/core/src/http/adapter/InversifyHttpAdapter.ts @@ -5,12 +5,15 @@ import { Container, Newable } from 'inversify'; import { InversifyHttpAdapterError } from '../../error/models/InversifyHttpAdapterError'; import { InversifyHttpAdapterErrorKind } from '../../error/models/InversifyHttpAdapterErrorKind'; +import { buildMiddlewareOptionsFromApplyMiddlewareOptions } from '../../routerExplorer/calculations/buildMiddlewareOptionsFromApplyMiddlewareOptions'; import { buildRouterExplorerControllerMetadataList } from '../../routerExplorer/calculations/buildRouterExplorerControllerMetadataList'; import { ControllerMethodParameterMetadata } from '../../routerExplorer/model/ControllerMethodParameterMetadata'; +import { MiddlewareOptions } from '../../routerExplorer/model/MiddlewareOptions'; import { RouterExplorerControllerMetadata } from '../../routerExplorer/model/RouterExplorerControllerMetadata'; import { RouterExplorerControllerMethodMetadata } from '../../routerExplorer/model/RouterExplorerControllerMethodMetadata'; import { Guard } from '../guard/model/Guard'; import { Middleware } from '../middleware/model/Middleware'; +import { ApplyMiddlewareOptions } from '../models/ApplyMiddlewareOptions'; import { Controller } from '../models/Controller'; import { ControllerResponse } from '../models/ControllerResponse'; import { HttpAdapterOptions } from '../models/HttpAdapterOptions'; @@ -34,14 +37,36 @@ const DEFAULT_ERROR_MESSAGE: string = 'An unexpected error occurred'; export abstract class InversifyHttpAdapter< TRequest, TResponse, - TNextFunction extends (err?: unknown) => Promise | void, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TNextFunction extends (err?: any) => Promise | void, TResult, > { protected readonly httpAdapterOptions: InternalHttpAdapterOptions; + protected readonly globalHandlers: { + preHandlerMiddlewareList: MiddlewareHandler< + TRequest, + TResponse, + TNextFunction, + TResult + >[]; + postHandlerMiddlewareList: MiddlewareHandler< + TRequest, + TResponse, + TNextFunction, + TResult + >[]; + guardList: MiddlewareHandler< + TRequest, + TResponse, + TNextFunction, + TResult | undefined + >[]; + }; readonly #awaitableRequestMethodParamTypes: Set; readonly #container: Container; readonly #logger: Logger; readonly #globalPipeList: (Newable | Pipe)[]; + #isBuilt: boolean; constructor( container: Container, @@ -57,6 +82,65 @@ export abstract class InversifyHttpAdapter< this.#logger = this.#buildLogger(httpAdapterOptions); this.httpAdapterOptions = this.#parseHttpAdapterOptions(httpAdapterOptions); this.#globalPipeList = []; + this.#isBuilt = false; + this.globalHandlers = { + guardList: [], + postHandlerMiddlewareList: [], + preHandlerMiddlewareList: [], + }; + } + + public async applyGlobalMiddleware( + ...middlewareList: (Newable | ApplyMiddlewareOptions)[] + ): Promise { + if (this.#isBuilt) { + throw new InversifyHttpAdapterError( + InversifyHttpAdapterErrorKind.invalidOperationAfterBuild, + 'Cannot apply global middleware after the server has been built', + ); + } + + const middlewareOptions: MiddlewareOptions = + buildMiddlewareOptionsFromApplyMiddlewareOptions(middlewareList); + + const [preHandlerMiddlewareList, postHandlerMiddlewareList]: [ + MiddlewareHandler[], + MiddlewareHandler[], + ] = await Promise.all([ + this.#getMiddlewareHandlerFromMetadata( + middlewareOptions.preHandlerMiddlewareList, + ), + this.#getMiddlewareHandlerFromMetadata( + middlewareOptions.postHandlerMiddlewareList, + ), + ]); + + this.globalHandlers.preHandlerMiddlewareList.push( + ...preHandlerMiddlewareList, + ); + this.globalHandlers.postHandlerMiddlewareList.push( + ...postHandlerMiddlewareList, + ); + } + + public async applyGlobalGuards( + ...guardList: Newable>[] + ): Promise { + if (this.#isBuilt) { + throw new InversifyHttpAdapterError( + InversifyHttpAdapterErrorKind.invalidOperationAfterBuild, + 'Cannot apply global guard after the server has been built', + ); + } + + const guardHandlerList: MiddlewareHandler< + TRequest, + TResponse, + TNextFunction, + TResult | undefined + >[] = await this.#getGuardHandlerFromMetadata(guardList); + + this.globalHandlers.guardList.push(...guardHandlerList); } public useGlobalPipe(...pipeList: (Newable | Pipe)[]): void { @@ -65,6 +149,8 @@ export abstract class InversifyHttpAdapter< protected async _buildServer(): Promise { await this.#registerControllers(); + + this.#isBuilt = true; } async #appendHandlerParam( diff --git a/packages/http/libraries/express-v4/src/adapter/InversifyExpressHttpAdapter.ts b/packages/http/libraries/express-v4/src/adapter/InversifyExpressHttpAdapter.ts index a0ea30df5..e4ec3527b 100644 --- a/packages/http/libraries/express-v4/src/adapter/InversifyExpressHttpAdapter.ts +++ b/packages/http/libraries/express-v4/src/adapter/InversifyExpressHttpAdapter.ts @@ -51,23 +51,32 @@ export class InversifyExpressHttpAdapter extends InversifyHttpAdapter< Response, NextFunction, void - >[] = [...routerParams.guardList, ...routerParams.preHandlerMiddlewareList]; + >[] = [ + ...this.globalHandlers.guardList, + ...routerParams.guardList, + ...this.globalHandlers.preHandlerMiddlewareList, + ...routerParams.preHandlerMiddlewareList, + ]; if (orderedMiddlewareList.length > 0) { router.use(orderedMiddlewareList); } for (const routeParams of routerParams.routeParamsList) { - const orderedPreHandlerMiddlewareList: - | MiddlewareHandler[] - | undefined = [ - ...routeParams.guardList, - ...routeParams.preHandlerMiddlewareList, - ]; - - const orderedPostHandlerMiddlewareList: - | MiddlewareHandler[] - | undefined = [ + const orderedPreHandlerMiddlewareList: MiddlewareHandler< + Request, + Response, + NextFunction, + void + >[] = [...routeParams.guardList, ...routeParams.preHandlerMiddlewareList]; + + const orderedPostHandlerMiddlewareList: MiddlewareHandler< + Request, + Response, + NextFunction, + void + >[] = [ + ...this.globalHandlers.postHandlerMiddlewareList, ...routerParams.postHandlerMiddlewareList, ...routeParams.postHandlerMiddlewareList, ]; diff --git a/packages/http/libraries/express/src/adapter/InversifyExpressHttpAdapter.ts b/packages/http/libraries/express/src/adapter/InversifyExpressHttpAdapter.ts index a0ea30df5..e4ec3527b 100644 --- a/packages/http/libraries/express/src/adapter/InversifyExpressHttpAdapter.ts +++ b/packages/http/libraries/express/src/adapter/InversifyExpressHttpAdapter.ts @@ -51,23 +51,32 @@ export class InversifyExpressHttpAdapter extends InversifyHttpAdapter< Response, NextFunction, void - >[] = [...routerParams.guardList, ...routerParams.preHandlerMiddlewareList]; + >[] = [ + ...this.globalHandlers.guardList, + ...routerParams.guardList, + ...this.globalHandlers.preHandlerMiddlewareList, + ...routerParams.preHandlerMiddlewareList, + ]; if (orderedMiddlewareList.length > 0) { router.use(orderedMiddlewareList); } for (const routeParams of routerParams.routeParamsList) { - const orderedPreHandlerMiddlewareList: - | MiddlewareHandler[] - | undefined = [ - ...routeParams.guardList, - ...routeParams.preHandlerMiddlewareList, - ]; - - const orderedPostHandlerMiddlewareList: - | MiddlewareHandler[] - | undefined = [ + const orderedPreHandlerMiddlewareList: MiddlewareHandler< + Request, + Response, + NextFunction, + void + >[] = [...routeParams.guardList, ...routeParams.preHandlerMiddlewareList]; + + const orderedPostHandlerMiddlewareList: MiddlewareHandler< + Request, + Response, + NextFunction, + void + >[] = [ + ...this.globalHandlers.postHandlerMiddlewareList, ...routerParams.postHandlerMiddlewareList, ...routeParams.postHandlerMiddlewareList, ]; diff --git a/packages/http/libraries/fastify/src/adapter/InversifyFastifyHttpAdapter.ts b/packages/http/libraries/fastify/src/adapter/InversifyFastifyHttpAdapter.ts index ce981540c..4f3a83950 100644 --- a/packages/http/libraries/fastify/src/adapter/InversifyFastifyHttpAdapter.ts +++ b/packages/http/libraries/fastify/src/adapter/InversifyFastifyHttpAdapter.ts @@ -15,6 +15,7 @@ import { FastifyPluginCallback, FastifyReply, FastifyRequest, + HookHandlerDoneFunction, onResponseAsyncHookHandler, preHandlerAsyncHookHandler, RouteHandlerMethod, @@ -24,7 +25,7 @@ import { Container } from 'inversify'; export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< FastifyRequest, FastifyReply, - (err?: unknown) => void, + HookHandlerDoneFunction, void > { readonly #app: FastifyInstance; @@ -140,23 +141,36 @@ export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< _opts: Record, done: () => void, ) => { - const orderedMiddlewareList: MiddlewareHandler< + const orderedPreHandlerMiddlewareList: MiddlewareHandler< FastifyRequest, FastifyReply, - (err?: Error) => void + (err?: Error) => void, + void >[] = [ + ...this.globalHandlers.preHandlerMiddlewareList, ...routerParams.guardList, + ...this.globalHandlers.preHandlerMiddlewareList, ...routerParams.preHandlerMiddlewareList, ]; - for (const middleware of orderedMiddlewareList) { + const orderedPostHandlerMiddlewareList: MiddlewareHandler< + FastifyRequest, + FastifyReply, + (err?: Error) => void, + void + >[] = [ + ...this.globalHandlers.postHandlerMiddlewareList, + ...routerParams.postHandlerMiddlewareList, + ]; + + for (const middleware of orderedPreHandlerMiddlewareList) { fastifyInstance.addHook( 'preHandler', this.#buildFastifyPreHandlerAsyncMiddleware(middleware), ); } - for (const middleware of routerParams.postHandlerMiddlewareList) { + for (const middleware of orderedPostHandlerMiddlewareList) { fastifyInstance.addHook( 'onResponse', this.#buildFastifyOnResponseAsyncMiddleware(middleware), @@ -238,7 +252,7 @@ export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< middlewareList: MiddlewareHandler< FastifyRequest, FastifyReply, - (err?: Error) => void + HookHandlerDoneFunction >[], ): preHandlerAsyncHookHandler[] { return middlewareList.map( @@ -256,7 +270,7 @@ export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< middlewareList: MiddlewareHandler< FastifyRequest, FastifyReply, - (err?: Error) => void + HookHandlerDoneFunction >[], ): onResponseAsyncHookHandler[] { return middlewareList.map( @@ -274,7 +288,7 @@ export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< middleware: MiddlewareHandler< FastifyRequest, FastifyReply, - (err?: Error) => void + HookHandlerDoneFunction >, ): preHandlerAsyncHookHandler { return async (request: FastifyRequest, reply: FastifyReply) => { @@ -301,7 +315,7 @@ export class InversifyFastifyHttpAdapter extends InversifyHttpAdapter< middleware: MiddlewareHandler< FastifyRequest, FastifyReply, - (err?: Error) => void + HookHandlerDoneFunction >, ): onResponseAsyncHookHandler { return async (request: FastifyRequest, reply: FastifyReply) => { diff --git a/packages/http/libraries/hono/src/adapter/InversifyHonoHttpAdapter.ts b/packages/http/libraries/hono/src/adapter/InversifyHonoHttpAdapter.ts index d953409ee..eeb4e909e 100644 --- a/packages/http/libraries/hono/src/adapter/InversifyHonoHttpAdapter.ts +++ b/packages/http/libraries/hono/src/adapter/InversifyHonoHttpAdapter.ts @@ -57,8 +57,17 @@ export class InversifyHonoHttpAdapter extends InversifyHttpAdapter< const router: Hono = new Hono(); const routerHonoMiddlewareList: HonoMiddlewareHandler[] = [ - ...this.#buildHonoMiddlewareList(routerParams.guardList), - ...this.#buildHonoMiddlewareList(routerParams.preHandlerMiddlewareList), + ...this.#buildHonoPreHandlerMiddlewareList(this.globalHandlers.guardList), + ...this.#buildHonoPreHandlerMiddlewareList(routerParams.guardList), + ...this.#buildHonoPreHandlerMiddlewareList( + this.globalHandlers.preHandlerMiddlewareList, + ), + ...this.#buildHonoPreHandlerMiddlewareList( + routerParams.preHandlerMiddlewareList, + ), + ...this.#buildHonoPostHandlerMiddlewareList( + this.globalHandlers.postHandlerMiddlewareList, + ), ...this.#buildHonoPostHandlerMiddlewareList( routerParams.postHandlerMiddlewareList, ), @@ -70,8 +79,10 @@ export class InversifyHonoHttpAdapter extends InversifyHttpAdapter< for (const routeParams of routerParams.routeParamsList) { const routeHonoMiddlewareList: HonoMiddlewareHandler[] = [ - ...this.#buildHonoMiddlewareList(routeParams.guardList), - ...this.#buildHonoMiddlewareList(routeParams.preHandlerMiddlewareList), + ...this.#buildHonoPreHandlerMiddlewareList(routeParams.guardList), + ...this.#buildHonoPreHandlerMiddlewareList( + routeParams.preHandlerMiddlewareList, + ), ...this.#buildHonoPostHandlerMiddlewareList( routeParams.postHandlerMiddlewareList, ), @@ -187,7 +198,7 @@ export class InversifyHonoHttpAdapter extends InversifyHttpAdapter< handler(ctx.req as HonoRequest, ctx, next); } - #buildHonoMiddlewareList( + #buildHonoPreHandlerMiddlewareList( handlers: MiddlewareHandler< HonoRequest, Context,