From ff4941c311c27141c564704d2048526a3f956a07 Mon Sep 17 00:00:00 2001 From: Etienne Noel Date: Sat, 13 Jan 2024 13:57:06 -0800 Subject: [PATCH] - Replaced the decorators metadata with reflect-metadata. --- .../common/src/utils/metadata.util.spec.ts | 4 +- packages/common/src/utils/metadata.util.ts | 5 +- .../src/decorators/controller.decorator.ts | 2 +- .../src/decorators/route.decorator.ts | 4 + .../response-headers.interceptor.ts | 5 +- packages/networking/src/router.ts | 93 ++++++++++--------- .../src/managers/authentication.manager.ts | 6 +- .../src/managers/authorizer.manager.ts | 6 +- .../decorators/body-validation.decorator.ts | 3 +- ...ody-validation.request-interceptor.spec.ts | 15 +-- .../body-validation.request-interceptor.ts | 7 +- 11 files changed, 85 insertions(+), 65 deletions(-) diff --git a/packages/common/src/utils/metadata.util.spec.ts b/packages/common/src/utils/metadata.util.spec.ts index d49dab1fd..02bc8eae1 100644 --- a/packages/common/src/utils/metadata.util.spec.ts +++ b/packages/common/src/utils/metadata.util.spec.ts @@ -53,13 +53,13 @@ describe("Metadata Util", () =>{ expect(routeContextAtTargetLevel["keyname"]).toBe("value") - MetadataUtil.setToRouteContext("keyname", "value", ClassWithEmptyMethod, "emptyMethod"); + MetadataUtil.setToRouteContext("keyname1", "value1", ClassWithEmptyMethod, "emptyMethod"); const routeContextAtPropertyLevel = MetadataUtil.getRouteContext(ClassWithEmptyMethod, "emptyMethod"); expect(typeof routeContextAtPropertyLevel).toBe("object"); expect(Object.keys(routeContextAtPropertyLevel).length).toBe(1) - expect(routeContextAtPropertyLevel["keyname"]).toBe("value") + expect(routeContextAtPropertyLevel["keyname1"]).toBe("value1") }) it("should append to the Target metadata", () => { diff --git a/packages/common/src/utils/metadata.util.ts b/packages/common/src/utils/metadata.util.ts index 4d0208cb3..81de7023c 100644 --- a/packages/common/src/utils/metadata.util.ts +++ b/packages/common/src/utils/metadata.util.ts @@ -45,7 +45,7 @@ export class MetadataUtil { let routeContext; if(propertyKey === undefined) { - routeContext = Reflect.getMetadata(routeContextMetadataKeynameConstant, target); + routeContext = Reflect.getMetadata(routeContextMetadataKeynameConstant, target.prototype); } else { routeContext = Reflect.getMetadata(routeContextMetadataKeynameConstant, target, propertyKey); } @@ -72,7 +72,8 @@ export class MetadataUtil { routeContext[metadataKeyname] = metadata; if(propertyKey === undefined) { - Reflect.defineMetadata(routeContextMetadataKeynameConstant, routeContext, target) + // When there are no properties, the metadata is defined on the prototype. + Reflect.defineMetadata(routeContextMetadataKeynameConstant, routeContext, target.prototype) } else { Reflect.defineMetadata(routeContextMetadataKeynameConstant, routeContext, target, propertyKey); } diff --git a/packages/networking/src/decorators/controller.decorator.ts b/packages/networking/src/decorators/controller.decorator.ts index e8b34bed8..3b9cc32d4 100644 --- a/packages/networking/src/decorators/controller.decorator.ts +++ b/packages/networking/src/decorators/controller.decorator.ts @@ -15,7 +15,7 @@ export const controller = (basePath: string) => { */ constructor: Function ) => { - Reflect.defineMetadata(basePathMetadataKeyname, basePath, constructor); + Reflect.defineMetadata(basePathMetadataKeyname, basePath, constructor.prototype); // Push the class prototype in the controllerRegistry that is used to instantiate all the controllers for the router. controllerRegistry.push(constructor.prototype) diff --git a/packages/networking/src/decorators/route.decorator.ts b/packages/networking/src/decorators/route.decorator.ts index 1177e373c..aa0e2c375 100644 --- a/packages/networking/src/decorators/route.decorator.ts +++ b/packages/networking/src/decorators/route.decorator.ts @@ -36,6 +36,10 @@ export const route = (httpMethod: HttpMethod | string, path: string) => { } Reflect.defineMetadata(routeMetadataKeyname, route, target, propertyKey); + const a = Reflect.hasMetadata(routeMetadataKeyname, target, propertyKey); + const b = routeMetadataKeyname; + const c = target; + const d = propertyKey; MetadataUtil.appendToTargetMetadata(target, routesControllerMetadataKeyname, propertyKey); }; diff --git a/packages/networking/src/interceptors/response-headers.interceptor.ts b/packages/networking/src/interceptors/response-headers.interceptor.ts index 1992060f3..7d33e776e 100644 --- a/packages/networking/src/interceptors/response-headers.interceptor.ts +++ b/packages/networking/src/interceptors/response-headers.interceptor.ts @@ -3,6 +3,7 @@ import {NetworkingModuleKeyname} from "../networking.module.keyname"; import {MethodRouterNode} from "../nodes/method-router.node"; import {RequestInterceptorInterface} from "../interfaces/request-interceptor.interface"; import {injectable} from "tsyringe"; +import {responseHeaderMetadataKeyname} from "../decorators/response-header.decorator"; /** * The Response Interceptor intercepts the response of the router by adding the response headers specified by the response header decorator. * It is tagged as a RequestInterceptor so it can be automatically injected with the all the other RequestInterceptor. @@ -19,8 +20,8 @@ export class ResponseHeadersInterceptor implements RequestInterceptorInterface { * @param methodNode The methode node. */ async interceptResponse(response: Response, request: Request, methodNode?: MethodRouterNode): Promise { - if(methodNode && methodNode.route.context && methodNode.route.context.hasOwnProperty("responseHeaders")){ - response.setHeaders({...response.headers, ...methodNode.route.context.responseHeaders}); + if(methodNode && methodNode.route.context && methodNode.route.context.hasOwnProperty(responseHeaderMetadataKeyname)){ + response.setHeaders({...response.headers, ...methodNode.route.context[responseHeaderMetadataKeyname]}); } return response; diff --git a/packages/networking/src/router.ts b/packages/networking/src/router.ts index f75ee9595..c206ca4af 100644 --- a/packages/networking/src/router.ts +++ b/packages/networking/src/router.ts @@ -9,7 +9,7 @@ import {Route} from "./models/route"; import {MethodRouterNode} from "./nodes/method-router.node"; import {ForbiddenHttpError} from "./errors/forbidden.http-error"; import {ControllerMethodParameterDecoratorResolver} from "./resolvers/controller-method-parameter-decorator.resolver"; -import { URL } from 'url'; +import {URL} from 'url'; import { tag, HttpMethod, @@ -17,7 +17,7 @@ import { ServiceDefinitionTagEnum, Request, Response, - MetadataUtil + MetadataUtil, routeContextMetadataKeynameConstant } from "@pristine-ts/common"; import {AuthenticationManagerInterface, AuthorizerManagerInterface} from "@pristine-ts/security"; import {LogHandlerInterface} from "@pristine-ts/logging"; @@ -53,11 +53,11 @@ export class Router implements RouterInterface { * @param authorizerManager The authorizer manager to validate authorization. * @param authenticationManager The authentication manager to validate authentication. */ - public constructor( @inject("LogHandlerInterface") private readonly loghandler: LogHandlerInterface, - private readonly controllerMethodParameterDecoratorResolver: ControllerMethodParameterDecoratorResolver, - @inject("AuthorizerManagerInterface") private readonly authorizerManager: AuthorizerManagerInterface, - @inject("AuthenticationManagerInterface") private readonly authenticationManager: AuthenticationManagerInterface, - private readonly cache: RouterCache) { + public constructor(@inject("LogHandlerInterface") private readonly loghandler: LogHandlerInterface, + private readonly controllerMethodParameterDecoratorResolver: ControllerMethodParameterDecoratorResolver, + @inject("AuthorizerManagerInterface") private readonly authorizerManager: AuthorizerManagerInterface, + @inject("AuthenticationManagerInterface") private readonly authenticationManager: AuthenticationManagerInterface, + private readonly cache: RouterCache) { } /** @@ -77,17 +77,17 @@ export class Router implements RouterInterface { * @param level The level at which we are at. */ private getRouteTreeLevel(node: RouterNode, message: string, level: number): string { - for(const child of node.children) { - for(let i = 0; i < level; i++){ - message+="\t"; + for (const child of node.children) { + for (let i = 0; i < level; i++) { + message += "\t"; } - if(child instanceof PathRouterNode){ - message+="--" + child.path + "\n"; + if (child instanceof PathRouterNode) { + message += "--" + child.path + "\n"; } - if(child instanceof MethodRouterNode){ - message+="--" + child.method + "\n"; + if (child instanceof MethodRouterNode) { + message += "--" + child.method + "\n"; } - message = this.getRouteTreeLevel(child, message, level+1); + message = this.getRouteTreeLevel(child, message, level + 1); } return message; } @@ -112,31 +112,26 @@ export class Router implements RouterInterface { // * @private // */ public setup() { - if(this.setupCompleted) { + if (this.setupCompleted) { return; } // Loop over all the controllers and control the Route Tree controllerRegistry.forEach(controller => { - if(Reflect.hasMetadata(basePathMetadataKeyname, controller) === false) { - return; - } - - let basePath: string = Reflect.getMetadata(basePathMetadataKeyname, controller); + let basePath: string = Reflect.getOwnMetadata(basePathMetadataKeyname, controller) ?? ""; // Clean the base path by removing trailing slashes. if (basePath.endsWith("/")) { basePath = basePath.slice(0, basePath.length - 1); } - const routePropertyKeys = Reflect.getMetadata(routesControllerMetadataKeyname, controller); + const routePropertyKeys: string[] = Reflect.getMetadata(routesControllerMetadataKeyname, controller); - for (const methodPropertyKey in routePropertyKeys) { - if(Reflect.hasMetadata(routeMetadataKeyname, controller, methodPropertyKey) === false) { - continue; + routePropertyKeys.forEach(methodPropertyKey => { + if (Reflect.hasMetadata(routeMetadataKeyname, controller, methodPropertyKey) === false) { + return; } - // Retrieve the "RouteMethodDecorator" object assigned by the @route decorator at .route const routeMethodDecorator: RouteMethodDecorator = Reflect.getMetadata(routeMetadataKeyname, controller, methodPropertyKey); @@ -144,7 +139,8 @@ export class Router implements RouterInterface { // the appropriate controller method const route = new Route(controller.constructor, routeMethodDecorator.methodKeyname); route.methodArguments = MetadataUtil.getMethodParametersMetadata(controller, methodPropertyKey); - route.context = mergeWith({}, MetadataUtil.getRouteContext(controller), MetadataUtil.getRouteContext(controller, methodPropertyKey)); + const context = mergeWith({}, MetadataUtil.getRouteContext(controller.constructor), MetadataUtil.getRouteContext(controller, methodPropertyKey)); + route.context = context; // Build the proper path let path = routeMethodDecorator.path; @@ -163,7 +159,9 @@ export class Router implements RouterInterface { // Register the route this.register(routePath, routeMethodDecorator.httpMethod, route); - } + + }) + }) this.setupCompleted = true; @@ -204,7 +202,7 @@ export class Router implements RouterInterface { let methodNode: MethodRouterNode | undefined = cachedRouterRoute?.methodNode; - if(methodNode === undefined) { + if (methodNode === undefined) { const methodNodeSpan = tracingManager.startSpan(SpanKeynameEnum.RouterFindMethodRouterNode, SpanKeynameEnum.RouterRequestExecution); // Retrieve the node to have information about the controller methodNode = this.root.find(splitPath, request.httpMethod) as MethodRouterNode; @@ -222,7 +220,7 @@ export class Router implements RouterInterface { }, NetworkingModuleKeyname); // If node doesn't exist, throw a 404 error - if(methodNode === null) { + if (methodNode === null) { this.loghandler.error("Cannot find the path", { rootNode: this.root, request, @@ -236,7 +234,7 @@ export class Router implements RouterInterface { // Get the route parameters const routeParameters = cachedRouterRoute?.routeParameters ?? (methodNode.parent as PathRouterNode).getRouteParameters(splitPath.reverse()); - if(cachedRouterRoute !== undefined && cachedRouterRoute.routeParameters === undefined) { + if (cachedRouterRoute !== undefined && cachedRouterRoute.routeParameters === undefined) { cachedRouterRoute.routeParameters = routeParameters; } @@ -270,7 +268,7 @@ export class Router implements RouterInterface { }, NetworkingModuleKeyname); // Todo: check if the error is an UnauthorizedHttpError, else create one. - if(error instanceof ForbiddenHttpError === false){ + if (error instanceof ForbiddenHttpError === false) { error = new ForbiddenHttpError("You are not allowed to access this."); } @@ -282,7 +280,7 @@ export class Router implements RouterInterface { try { // Verify that the identity making the request is authorized to make such a request - if(await this.authorizerManager.isAuthorized(request, methodNode.route.context, container, identity) === false) { + if (await this.authorizerManager.isAuthorized(request, methodNode.route.context, container, identity) === false) { this.loghandler.error("User not authorized to access this url.", { request, context: methodNode.route.context, @@ -308,7 +306,7 @@ export class Router implements RouterInterface { let resolvedMethodArguments: any[] | undefined = this.cache.getCachedControllerMethodArguments(cacheKeyname, interceptedRequest); // If the cache did not contain the cached controller method arguments - if(resolvedMethodArguments === undefined) { + if (resolvedMethodArguments === undefined) { this.loghandler.debug("Resolved method arguments were not cached, currently resolving", { request, interceptedRequest, @@ -346,7 +344,7 @@ export class Router implements RouterInterface { let returnedResponse: Response; // If the response is already a Response object, return the response - if(response instanceof Response) { + if (response instanceof Response) { this.loghandler.debug("Router - Response returned by the controller is a Response object", { response, }, NetworkingModuleKeyname) @@ -375,8 +373,7 @@ export class Router implements RouterInterface { routerRequestExecutionSpan.end(); return resolve(interceptedResponse); - } - catch (error) { + } catch (error) { this.loghandler.error("Router - There was an error trying to execute the request in the router", { error, }, NetworkingModuleKeyname) @@ -399,7 +396,7 @@ export class Router implements RouterInterface { * @param methodNode * @private */ - private async executeRequestInterceptors( request: Request, container: DependencyContainer, methodNode: MethodRouterNode): Promise { + private async executeRequestInterceptors(request: Request, container: DependencyContainer, methodNode: MethodRouterNode): Promise { this.loghandler.debug("Router - Request Interceptors - Start", { request, methodNode, @@ -417,7 +414,10 @@ export class Router implements RouterInterface { // So, we have to verify that the method exists, and if it doesn't we throw if (typeof interceptor.interceptRequest === "undefined") { // Simply log a message for now that the interceptors doesn't implement the 'interceptRequest' method. - this.loghandler.debug("The Request Interceptor doesn't implement the interceptRequest method.", {name: interceptor.constructor.name, interceptor}); + this.loghandler.debug("The Request Interceptor doesn't implement the interceptRequest method.", { + name: interceptor.constructor.name, + interceptor + }); continue; } @@ -469,7 +469,10 @@ export class Router implements RouterInterface { // So, we have to verify that the method exists, and if it doesn't we throw if (typeof interceptor.interceptResponse === "undefined") { // Simply log a message for now that the interceptors doesn't implement the 'interceptResponse' method. - this.loghandler.debug("Router - The Request Interceptor doesn't implement the interceptResponse method.", {name: interceptor.constructor.name, interceptor}, NetworkingModuleKeyname); + this.loghandler.debug("Router - The Request Interceptor doesn't implement the interceptResponse method.", { + name: interceptor.constructor.name, + interceptor + }, NetworkingModuleKeyname); continue; } @@ -511,7 +514,7 @@ export class Router implements RouterInterface { // Execute all the request interceptors let interceptedResponse = new Response(); - if(error instanceof HttpError) { + if (error instanceof HttpError) { interceptedResponse.status = error.httpStatus; interceptedResponse.body = { name: error.name, @@ -520,8 +523,7 @@ export class Router implements RouterInterface { errors: error.errors, extra: error.extra, } - } - else { + } else { interceptedResponse.status = 500; interceptedResponse.body = {name: error.name, message: error.message, stack: error.stack}; } @@ -537,7 +539,10 @@ export class Router implements RouterInterface { // So, we have to verify that the method exists, and if it doesn't we throw if (typeof interceptor.interceptError === "undefined") { // Simply log a message for now that the interceptors doesn't implement the 'interceptError' method. - this.loghandler.info("The Request Interceptor doesn't implement the interceptError method.", {name: interceptor.constructor.name, interceptor}); + this.loghandler.info("The Request Interceptor doesn't implement the interceptError method.", { + name: interceptor.constructor.name, + interceptor + }); continue; } diff --git a/packages/security/src/managers/authentication.manager.ts b/packages/security/src/managers/authentication.manager.ts index 34f8210c5..fab2279f8 100644 --- a/packages/security/src/managers/authentication.manager.ts +++ b/packages/security/src/managers/authentication.manager.ts @@ -8,6 +8,7 @@ import {AuthenticatorFactory} from "../factories/authenticator.factory"; import {SecurityModuleKeyname} from "../security.module.keyname"; import {IdentityProviderInterface} from "../interfaces/identity-provider.interface"; import {Request} from "@pristine-ts/common"; +import {authenticatorMetadataKeyname} from "../decorators/authenticator.decorator"; /** * The authentication manager provides authentication by returning the identity executing the action. @@ -37,13 +38,14 @@ export class AuthenticationManager implements AuthenticationManagerInterface { * @param container The dependency container from which to resolve the authenticator. */ public async authenticate(request: Request, routeContext: any, container: DependencyContainer): Promise { - if(!routeContext || routeContext.authenticator === undefined) { + const authenticator = routeContext[authenticatorMetadataKeyname]; + if(!routeContext || authenticator === undefined) { return undefined; } let identity: IdentityInterface | undefined; - const authenticatorContext: AuthenticatorContextInterface = routeContext.authenticator; + const authenticatorContext: AuthenticatorContextInterface = authenticator; try { const instantiatedAuthenticator: AuthenticatorInterface = this.authenticatorFactory.fromContext(authenticatorContext, container); diff --git a/packages/security/src/managers/authorizer.manager.ts b/packages/security/src/managers/authorizer.manager.ts index e1a30e337..8d24b65e1 100644 --- a/packages/security/src/managers/authorizer.manager.ts +++ b/packages/security/src/managers/authorizer.manager.ts @@ -5,6 +5,7 @@ import {AuthorizerManagerInterface} from "../interfaces/authorizer-manager.inter import {GuardFactory} from "../factories/guard.factory"; import {SecurityModuleKeyname} from "../security.module.keyname"; import {Request} from "@pristine-ts/common"; +import {guardMetadataKeyname} from "../decorators/guard.decorator"; /** * The authorizer manager provides authorization by authorizing the action. @@ -33,13 +34,14 @@ export class AuthorizerManager implements AuthorizerManagerInterface { */ public async isAuthorized(request: Request, routeContext: any, container: DependencyContainer, identity?: IdentityInterface): Promise { // If there are no guards defined, we simply return that it is authorized. - if(!routeContext || routeContext.guards === undefined || Array.isArray(routeContext.guards) === false) { + const guards = routeContext[guardMetadataKeyname]; + if(!routeContext || guards === undefined || Array.isArray(guards) === false) { return true; } let isAuthorized = true; - for (const guardContext of routeContext.guards) { + for (const guardContext of guards) { try { const instantiatedGuard = this.guardFactory.fromContext(guardContext, container); diff --git a/packages/validation/src/decorators/body-validation.decorator.ts b/packages/validation/src/decorators/body-validation.decorator.ts index 6238fa0b5..0cb4d7938 100644 --- a/packages/validation/src/decorators/body-validation.decorator.ts +++ b/packages/validation/src/decorators/body-validation.decorator.ts @@ -1,3 +1,4 @@ +import {MetadataUtil} from "@pristine-ts/common"; export const bodyValidationMetadataKeyname = "@bodyValidation"; @@ -22,7 +23,7 @@ export const bodyValidation = (classType: Function) => { */ descriptor: PropertyDescriptor ) => { - Reflect.defineMetadata(bodyValidationMetadataKeyname, { + MetadataUtil.setToRouteContext(bodyValidationMetadataKeyname, { classType, }, target, propertyKey); } diff --git a/packages/validation/src/interceptors/body-validation.request-interceptor.spec.ts b/packages/validation/src/interceptors/body-validation.request-interceptor.spec.ts index b71b93298..6fba6f5ab 100644 --- a/packages/validation/src/interceptors/body-validation.request-interceptor.spec.ts +++ b/packages/validation/src/interceptors/body-validation.request-interceptor.spec.ts @@ -4,6 +4,7 @@ import {MethodRouterNode, PathRouterNode, Route} from "@pristine-ts/networking"; import {HttpMethod, Request} from "@pristine-ts/common"; import {IsDate, IsInt, Max, Min, Validator} from "@pristine-ts/class-validator"; import {LogHandlerInterface} from "@pristine-ts/logging"; +import {bodyValidationMetadataKeyname} from "../decorators/body-validation.decorator"; describe("Body Validation Request Enricher", () => { const logHandlerMock: LogHandlerInterface = { @@ -32,7 +33,7 @@ describe("Body Validation Request Enricher", () => { const route: Route = new Route(null, "method"); route.context = {} - route.context.bodyValidator = undefined; + route.context[bodyValidationMetadataKeyname] = undefined; const methodRouterNode: MethodRouterNode = new MethodRouterNode(new PathRouterNode("/"), HttpMethod.Get, route, 1) @@ -48,8 +49,8 @@ describe("Body Validation Request Enricher", () => { const route: Route = new Route(null, "method"); route.context = {}; - route.context.bodyValidator = {}; - route.context.bodyValidator.classType = undefined; + route.context[bodyValidationMetadataKeyname] = {}; + route.context[bodyValidationMetadataKeyname].classType = undefined; const methodRouterNode: MethodRouterNode = new MethodRouterNode(new PathRouterNode("/"), HttpMethod.Get, route, 1) @@ -70,8 +71,8 @@ describe("Body Validation Request Enricher", () => { const route: Route = new Route(null, "method"); route.context = {}; - route.context.bodyValidator = {}; - route.context.bodyValidator.classType = BodyPayload; + route.context[bodyValidationMetadataKeyname] = {}; + route.context[bodyValidationMetadataKeyname].classType = BodyPayload; const methodRouterNode: MethodRouterNode = new MethodRouterNode(new PathRouterNode("/"), HttpMethod.Get, route, 1) @@ -91,8 +92,8 @@ describe("Body Validation Request Enricher", () => { const route: Route = new Route(null, "method"); route.context = {}; - route.context.bodyValidator = {}; - route.context.bodyValidator.classType = BodyPayload; + route.context[bodyValidationMetadataKeyname] = {}; + route.context[bodyValidationMetadataKeyname].classType = BodyPayload; const methodRouterNode: MethodRouterNode = new MethodRouterNode(new PathRouterNode("/"), HttpMethod.Get, route, 1) diff --git a/packages/validation/src/interceptors/body-validation.request-interceptor.ts b/packages/validation/src/interceptors/body-validation.request-interceptor.ts index 02e2e788e..b4cc79dc2 100644 --- a/packages/validation/src/interceptors/body-validation.request-interceptor.ts +++ b/packages/validation/src/interceptors/body-validation.request-interceptor.ts @@ -6,6 +6,7 @@ import {ValidationModuleKeyname} from "../validation.module.keyname"; import {injectable, inject} from "tsyringe"; import { plainToInstance } from 'class-transformer'; import {LogHandlerInterface} from "@pristine-ts/logging"; +import {bodyValidationMetadataKeyname} from "../decorators/body-validation.decorator"; /** * This class is an interceptor to validate the body of an incoming request. @@ -35,7 +36,9 @@ export class BodyValidationRequestInterceptor implements RequestInterceptorInter * @param methodNode The method node. */ async interceptRequest(request: Request, methodNode: MethodRouterNode): Promise { - if(methodNode.route.context.bodyValidator === undefined || methodNode.route.context.bodyValidator.classType === undefined) { + const bodyValidator = methodNode.route.context[bodyValidationMetadataKeyname]; + + if(bodyValidator === undefined || bodyValidator.classType === undefined) { return request; } @@ -46,7 +49,7 @@ export class BodyValidationRequestInterceptor implements RequestInterceptorInter }, ValidationModuleKeyname) // Validates that the body can be mapped to the expected type - const mappedBody = plainToInstance(methodNode.route.context.bodyValidator.classType, request.body); + const mappedBody = plainToInstance(bodyValidator.classType, request.body); // Validates if all the conditions are respected in the expected type. const errors = await this.validator.validate(mappedBody);