-
-
Save bengry/924a9b93c25d8a98bffdfc0a847f0dbe to your computer and use it in GitHub Desktop.
| import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common"; | |
| import { APP_INTERCEPTOR } from "@nestjs/core"; | |
| import { RequestContextMiddleware } from "./request-context/request-context.middleware"; | |
| import { RequestContextModule } from "./request-context/request-context.module"; | |
| @Module({ | |
| imports: [ | |
| ConfigModule.load(path.resolve(__dirname, "config", "**/!(*.d).{ts,js}")), | |
| WebappUsersModule, | |
| RequestContextModule, | |
| LoggerModule, | |
| ], | |
| ... | |
| }) | |
| export class AppModule { | |
| configure(consumer: MiddlewareConsumer) { | |
| consumer.apply(RequestContextMiddleware).forRoutes("*"); | |
| } | |
| } |
| import { Injectable, NestMiddleware } from "@nestjs/common"; | |
| import { Request, Response } from "express"; | |
| import { RequestContext } from "./request-context.model"; | |
| /** | |
| * This is needed to side-step Nest.js, which doesn't support getting the current execution context (i.e. Request) that's | |
| * not from the Controller handles directly (and passing it down explicitly). This means that things like a Logger can't | |
| * use DI to get the current user (if any). | |
| * | |
| * This solution is taken from https://github.com/nestjs/nest/issues/699#issuecomment-405868782. | |
| */ | |
| @Injectable() | |
| export class RequestContextMiddleware implements NestMiddleware<Request, Response> { | |
| use(req: Request, res: Response, next: () => void) { | |
| const requestContext = new RequestContext(req, res); | |
| RequestContext.cls.setContext(requestContext); | |
| next(); | |
| } | |
| } |
| import { ContinuationLocalStorage } from "asyncctx"; | |
| import { Request, Response } from "express"; | |
| export class RequestContext { | |
| static cls = new ContinuationLocalStorage<RequestContext>(); | |
| static get currentContext() { | |
| return this.cls.getContext(); | |
| } | |
| readonly requestId: number; | |
| constructor(public readonly req: Request, public readonly res: Response) { | |
| this.requestId = Date.now(); | |
| } | |
| } |
| import { Module } from "@nestjs/common"; | |
| import { RequestContextMiddleware } from "./request-context.middleware"; | |
| import { RequestContextService } from "./request-context.service"; | |
| @Module({ | |
| providers: [RequestContextMiddleware, RequestContextService], | |
| exports: [RequestContextMiddleware, RequestContextService], | |
| }) | |
| export class RequestContextModule {} |
| import { Injectable } from "@nestjs/common"; | |
| import { IUserDocument } from "../modules/webapp-users/interfaces"; | |
| import { RequestContext } from "./request-context.model"; | |
| @Injectable() | |
| export class RequestContextService { | |
| get currentUser(): IUserDocument | null { | |
| const requestContext = this.currentRequest; | |
| return (requestContext && requestContext.req.user) || null; | |
| } | |
| get currentRequestId(): number | null { | |
| const requestContext = this.currentRequest; | |
| return (requestContext && requestContext.requestId) || null; | |
| } | |
| private get currentRequest() { | |
| const requestContext = RequestContext.currentContext; | |
| return requestContext || null; | |
| } | |
| } |
| // This can be done anywhere. In my case I wanted to get the current user and requestId | |
| import { Injectable } from "@nestjs/common"; | |
| import { IUserDocument } from "../modules/webapp-users/interfaces"; | |
| import { RequestContext } from "./request-context.model"; | |
| @Injectable() | |
| export class RequestContextService { | |
| get currentUser(): IUserDocument | null { | |
| const requestContext = this.currentRequest; | |
| return (requestContext && requestContext.req.user) || null; | |
| } | |
| get currentRequestId(): number | null { | |
| const requestContext = this.currentRequest; | |
| return (requestContext && requestContext.requestId) || null; | |
| } | |
| private get currentRequest() { | |
| const requestContext = RequestContext.currentContext; // this is the actual usage. | |
| return requestContext || null; | |
| } | |
| } |
This won't work if multiple requests come in at the same time, and your code has any asynchronized processing.On further reading, this seems to be a working code. Thanks for sharing it! Reference: https://medium.com/@siddiqr67/async-hooks-the-coolest-way-to-save-execution-context-676d8af57f73
Hell yeah I got the exact same consideration…
I give more intel from your article:
Data can be shared between async context thanks to asyncctx library which is using async a experimental feature of node at this time I'm writing.
Now you can replace asyncctx with the new (Node12) API async local storage
They allow storing data throughout the lifetime of a web request or any other asynchronous duration. It is similar to thread-local storage in other languages.
This snippet can be replace by this library that use the "new" API : https://github.com/abonifacio/nestjs-request-context
For now you can use https://github.com/Papooch/nestjs-cls
@kieranongh Hi! I just want to help you that problem. You can inject your request-context service to subscriber or service (concise place that you want) and use it directly.