I am working on a NestJS project, I'm trying to get the executionContext accessible in a logger to filter the logs by request.
I have one logger instance per injectable, and I would like to keep this behavior (So the scope of the injectable is default).
To do this, I'm trying to create a decorator that gets the context from the request and passes it to the child services (as in the logger), to finally get the context in the logger...
I'm not sure to be clear... For now, here is my code:
export const Loggable = () => (constructor: Function) => {
for (const propertyName of Reflect.ownKeys(constructor.prototype)) {
let descriptor = Reflect.getOwnPropertyDescriptor(constructor.prototype, propertyName);
const isMethod = descriptor.value instanceof Function;
if (!isMethod)
continue;
const originalMethod = descriptor.value;
const routeArgsMetada = Reflect.getMetadata(ROUTE_ARGS_METADATA, constructor, propertyName as string);
descriptor.value = function (...args: any[]) {
const result = originalMethod.apply(this, args);
//TODO : retrieve the request / contextExecution
//TODO : pass the request / contextExecution to children functions...
return result;
};
Reflect.defineProperty(constructor.prototype, propertyName, descriptor);
Reflect.defineMetadata(ROUTE_ARGS_METADATA, routeArgsMetada, constructor, propertyName as string);
}
};
This @Loggable() decorator would be attached to all injectable classes that need to log or throw execution context
Is that possible ? If not why ?
PS: I'm wondering, how could the @Guard annotation get the context? and how could the @Req annotations get the request?
https://github.com/nestjs/nest/tree/master/packages/common/decorators/http
https://github.com/nestjs/nest/blob/master/packages/common/decorators/core/use-guards.decorator.ts
How @Req does get the Request?
Download source of NestJS from here: https://github.com/nestjs/nest
and look for 'RouteParamtypes.REQUEST' in TS files. You will find them here:
As you can see decorators generally don't do too much. They just add some metadata to classes, methods, and arguments. All the rest do the framework.
Here @Req only creates a special parameter decorator during startup which is processed by RouteParamsFactory before calling a method.
export const Request: () => ParameterDecorator = createRouteParamDecorator(
RouteParamtypes.REQUEST,
);
So Request is not retrieved by the @Req decorator itself. It only asks the NestJS framework to fill the annotated method parameter with reference of Request before calling the method.
BTW I also struggling with the same problem as you. I also was looking for a solution on how to access ExecutionContext from decorators. But decorators can access only annotated targets (classes, handlers, arguments, ...)
I think ExecutionContext only can be accessed directly from:
or from argument decorators this way: https://docs.nestjs.com/custom-decorators#param-decorators
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
NOTE: You can find source of createParamDecorator() in create-route-param-metadata.decorator.ts .