-
-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to access current http context inside component method #173
Comments
Hi @darioxtx, |
Hi @kamilmysliwiec, Each request have user object inside and i want to access that data in component and use current user object to filter data from database based on logged in user ex.:
An other place where I want to get user is
Thanks |
Hi @darioxtx, |
Thank you for your answer. I will share my experience solving this issue. |
Hi @darioxtx, @kamilmysliwiec, maybe Zone.js can be integrated in the framework? The zone will provide this request context if each request handler is run in a new zone. Then that can be injected in the components as RequestContext. BTW, request-context is implemented on top of the Node.js Domain API which is deprecated for quite some time. |
@darioxtx did you find any solution? |
@cdiaz yes my solution is to use Zone.js. it seems promising and is under angular team control. I can share code later if anyone interested. |
Great, I'm interested to see your code to know how to implement CurrentUser context. |
Hi, Here is my Zone.js integration with nest. first I import import 'zone.js';
import "zone.js/dist/zone-node.js";
import "zone.js/dist/long-stack-trace-zone.js"; Then I created import {Middleware, NestMiddleware} from '@nestjs/common';
import {RequestContext} from "../models/request-context";
@Middleware()
export class RequestContextMiddleware implements NestMiddleware {
constructor() {}
resolve() {
return(req, res, next) => {
var requestContext = new RequestContext(req, res);
Zone.current.fork({
name: RequestContext.name,
properties: {
[RequestContext.name]: requestContext
}
}).fork(Zone['longStackTraceZoneSpec']).run(async () => {
await next();
} );
}
}
}
import {CurrentUser} from "../../modules/auth/models/current-user";
export class RequestContext {
public readonly id: Number;
public request: Request;
public response: Response;
constructor(request: Request, response: Response) {
this.id = Math.random();
this.request = request;
this.response = response;
}
public static currentRequestContext(): RequestContext {
return Zone.current.get(RequestContext.name);
}
public static currentRequest(): Request {
let requestContext = RequestContext.currentRequestContext();
if(requestContext) {
return requestContext.request;
}
return null;
}
public static currentUser(): CurrentUser {
let requestContext = RequestContext.currentRequestContext();
if(requestContext) {
return requestContext.request['user'];
}
return null;
}
}
@Module({
modules: [AuthModule, UsersModule, DatabaseModule]
})
export class ApplicationModule {
configure(consumer: MiddlewaresConsumer) {
consumer
.apply(RequestContextMiddleware)
.forRoutes({path: "*"})
}
} Current import {EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent} from "typeorm";
import {RequestContext} from "../../common/models/request-context";
@EventSubscriber()
export class EverythingSubscriber implements EntitySubscriberInterface<any> {
beforeInsert(event: InsertEvent<any>) {
let currentUser = RequestContext.currentUser();
if(!currentUser) {
throw new Error("Unknown user context");
}
event.entity.updatedBy = currentUser.username;
event.entity.createdBy = currentUser.username;
event.entity.createdOn = new Date();
event.entity.updatedOn = new Date();
console.log(`user: `, currentUser.username);
console.log(`BEFORE ENTITY INSERTED: `, event.entity);
}
} I think that's it, also i like exception trace that provide @saskodh thanks for right directions. |
Great work @darioxtx ! |
Some weeks ago i tried zone.js in node to get the current user (and some other information). But zone.js often caused crashes when the app becomes complex. Therefore i upgraded to node 8.4 and used cls-hooked. The implementation works in a very similar way. |
@JustGreg, this is excellent, thanks for sharing, I wasn't aware that this API was added in Node.js. @kamilmysliwiec, this is excellent opportunity for adding new features that depend on the 'thread-local' storage like declarative transaction management. While it's in experimental phase Nest can leave the decision to the user whether he will enable this feature or not. What are your thoughts? |
Hi everyone, @saskodh since this API is still in experimental phase (stability: 1) I'm not gonna integrate it with nest in any way now. What I'm trying to do is to make sure that learning curve is not too big, so I see this feature as a 3rd-party module rather than the 'core thing'. |
Just for information: Another npm package (based on typescript) which uses async_hookes is https://github.com/gms1/node-async-context |
I'm trying to access a service from a typeorm EventSubscriber. |
@donaldinho Just export a Is that what you need? |
Can we just modify the |
@darioxtx I am trying to implement your solution (thanks for sharing!) However inside my controller Inside the middleware I noticed that
gives:
I don't have a I am compiling using es2017 Any thoughts on what I might do wrong here? |
Hi @basvdijk, import { HttpException, HttpStatus } from "@nestjs/common";
import * as cls from 'cls-hooked';
import { IncomingMessage } from "http";
import { CurrentUser } from "../../modules/models/current-user.model";
export class RequestContext {
public static nsid = 'some_random_guid';
public readonly id: Number;
public request: IncomingMessage;
public response: Response;
constructor(request: IncomingMessage, response: Response) {
this.id = Math.random();
this.request = request;
this.response = response;
}
public static currentRequestContext(): RequestContext {
const session = cls.getNamespace(RequestContext.nsid);
if (session && session.active) {
return session.get(RequestContext.name);
}
return null;
}
public static currentRequest(): IncomingMessage {
let requestContext = RequestContext.currentRequestContext();
if (requestContext) {
return requestContext.request;
}
return null;
}
public static currentUser(throwError?: boolean): CurrentUser {
let requestContext = RequestContext.currentRequestContext();
if (requestContext) {
const user: any = requestContext.request['user'];
if (user) {
return new CurrentUser(user);
}
}
if (throwError) {
throw new HttpException("Unauthorized", HttpStatus.UNAUTHORIZED);
}
return null;
}
} and Middleware looks like this import { Injectable, NestMiddleware } from '@nestjs/common';
import * as cls from 'cls-hooked';
import { RequestContext } from "../models/request-context";
@Injectable()
export class RequestContextMiddleware implements NestMiddleware {
resolve() {
return (req, res, next) => {
const requestContext = new RequestContext(req, res);
const session = cls.getNamespace(RequestContext.nsid) || cls.createNamespace(RequestContext.nsid);
session.run(async () => {
session.set(RequestContext.name, requestContext);
next();
})
}
}
} I hope this will help you :) |
@darioxtx Thanks I'll check it out. I was wondering if it smart to still use |
@darioxtx Applied your solution to my project and works like a charm 👍 |
This thread helped a lot, but after updating npm modules the solution with zone.js fell apart. I found another solution working with pg, node > 10 and async/await: node-request-context did the magic again with the following code: Middleware function: import {RequestContext} from "./request.context";
import { getNamespace, createNamespace } from 'node-request-context';
export function RequestContextMiddleware(req, res, next) {
let rc = new RequestContext(req, res);
const namespace = getNamespace('myapp.mynamespace') || createNamespace('myapp.mynamespace');
namespace.run(() => {
namespace.set('tid', rc);
next();
});
}; RequestContext import { AppUser } from "../../entities/appuser/appuser.entity";
import { getNamespace } from 'node-request-context';
export class RequestContext {
public readonly id: Number;
public request: Request;
public response: Response;
constructor(request: Request, response: Response) {
this.id = Math.random();
this.request = request;
this.response = response;
}
public static currentRequestContext(): RequestContext {
let namespace = getNamespace('myapp.mynamespace');
let rc = namespace.get('tid');
return rc;
}
public static currentRequest(): Request {
let requestContext = RequestContext.currentRequestContext();
return requestContext.request;
}
public static currentUser(): AppUser {
let requestContext = RequestContext.currentRequestContext();
return requestContext.request['user'];
}
} Middleware called globally import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';
import { RequestContextMiddleware } from './auth/zone/request.context.middleware';
import { frontenddispatcher } from './frontend.middleware2';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
app.use(RequestContextMiddleware, frontenddispatcher);
await app.listen(3000);
}
bootstrap(); Usage in EventSubscriber import {EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent} from "typeorm";
import { RequestContext } from "../auth/zone/request.context";
@EventSubscriber()
export class EverythingSubscriber implements EntitySubscriberInterface {
beforeInsert(event: InsertEvent<any>) {
let currentUser = RequestContext.currentUser();
console.log(JSON.stringify(currentUser))
if(!currentUser || !currentUser.email) {
throw new Error("Unknown user context");
}
event.entity.updatedBy = currentUser.email;
event.entity.createdBy = currentUser.email;
event.entity.createdOn = new Date();
event.entity.updatedOn = new Date();
console.log(`user: `, currentUser.email);
console.log(`BEFORE ENTITY INSERTED: `, event.entity);
}
beforeUpdate(event: UpdateEvent<any>) {
let currentUser = RequestContext.currentUser();
console.log(JSON.stringify(currentUser))
if(!currentUser || !currentUser.email) {
throw new Error("Unknown user context");
}
event.entity.updatedBy = currentUser.email;
event.entity.updatedOn = new Date();
console.log(`user: `, currentUser.email);
console.log(`BEFORE ENTITY UPDATED: `, event.entity);
}
} |
@heyplusyou thanks for this example. Since |
@zWaR Not with a customer in production but internally within my company. |
Is there any solution that's not based on |
Soon in the incoming Nest 6 release #1486 |
Thanks @kamilmysliwiec |
This comment has been minimized.
This comment has been minimized.
How would I do this in Nest 6 without async_hooks? |
You should be able to achieve that by injecting the request as @Inject(REQUEST) |
@adrien2p Can you provide a small example please? |
You just have to use the inject decorator to inject the request, for that you need to make your provider request scoped. from the injected request you only need to do this.request.user to access the current user on the request. But don’t forget to attach the user through a guard. I am out of the office and on the phone, hard to write an example ^^ for the request scoped i invite you to have a look on this link https://docs.nestjs.com/fundamentals/injection-scopes |
I am still stuck on this topic, can you help regarding this issue? Instead of using it for an ORM I need the current request everytime someone calls "logger.log"... |
@mambax you have to set your logger scope to |
Hello! If I add
Instead with this structure the event is fired, but I need request
Any suggestion? Thank you |
I know this issue is closed, but I got here by Google Search and also the last comment is pretty recent (16 days ago). @ants88 I do not have a suggestion, but what I am experiencing right now is: if service in the @kamilmysliwiec if I understand what you mention in your comment it almost looks like a bug to me. Should I open a new issue and add a test case for this? Since I need this badly too, I will try the other options suggested in this thread and update you with my findings. |
@kamilmysliwiec what do you think about introducing |
so........How to access current http context inside "typeorm" EventSubscriber class?????????? |
Just FYI right now I am using https://github.com/jeff-lewis/cls-hooked to pass the context I need (like Would be interested to know how this can be done better. |
Is this feature released in nest 6 release. If yes can we have a example how to do get request context in typeorm event subscribe class |
Is it already integrated? |
Hi,
How to access current http context inside component method?
As an example i would like to access current session user inside "typeorm" EventSubscriber class to automatically set user who inserted/update/deleted record.
Thanks for nice framework!
The text was updated successfully, but these errors were encountered: