Created
December 26, 2019 07:32
-
-
Save bengry/924a9b93c25d8a98bffdfc0a847f0dbe to your computer and use it in GitHub Desktop.
Nest.js request context workaround
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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("*"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
This snippet can be replace by this library that use the "new" API : https://github.com/abonifacio/nestjs-request-context