-
Notifications
You must be signed in to change notification settings - Fork 402
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
Support request-scoped, global enhancers #325
Comments
The |
I'm new to nest and I've been trying to write a db transaction interceptor for my graphql mutations, but these issues with no injections are causing me problems. |
@lnmunhoz @chrisregnier simply use controller-scoped or method-scoped interceptors instead of global ones. |
Actually I am using method scoped interceptors already and that's what's not working for me. I haven't tried the other scopes though so I'll give those a try. Thanks. |
@chrisregnier could you please create a separate issue + provide a reproduction repository? |
I've been trying all day to reproduce my problem in a small test case, but everything seems to be working. So I've clearly got unrelated problems in my own code. Thanks. |
I'm also getting the same issue as @kaihaase. Is there any timeline for fixing this issue? |
I just tested this w/ Nest V7 and was unable to get it to work with a request scoped Global Interceptor (via provider syntax) or w/ a request scope Global Guard. I'm able to get it to work w/ method level guards/interceptors but that's not an optimal solution. Is there any update w/ adding this feature? |
For anyone coming to this issue at the moment, request scoping an interceptor or guard doesn't make much sense because they already have access to the request object. What can be done, is inject the @Injectable()
export class InterceptorUsingReqScopedProvider implements NestInterceptor {
constructor(private readonly modRef: ModuleRef) {}
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<unknown>> {
const req = this.getRequest(context);
const contextId = ContextIdFactory.getByRequest(req);
const service = await modRef.resolve(ServiceName, contextId);
// do something with the service
return next.handle();
// can also work in the `.pipe` of the observable
}
getRequest(context: ExecutionContext) {
// this can have added logic to take care of REST and other contexts
const gql = GqlExecutionContext.create(context);
return gql.getContext().req;
}
} To make sure this works, you should also make sure to set up the context properly from the GraphqlModule.forRoot({
context: ({ req }) => ({ req }),
// other options
}) |
Just a small note:
Request scoping an interceptor or guard may make sense in case they depend on request-scoped providers which factory functions perform some complex, async operations. Using |
You're right. I think I was trying to say making these enhancers explicitly request scoped isn't necessary due to being able to use the |
As @jmcdo29 pointed out, it's not a big issue for interceptors or guards, because they already have access to execution context. However, I'm also experiencing the same issue with global pipes, and they don't have that access. I'm using NestJS 7.6.13. Use case for request-scoped global pipes - automatic validation of entities existence (by IDs) in databases split by tenants (SaaS). |
@kamilmysliwiec The ticket has been open for a while now and we are working with the latest nestjs packages (see below), but unfortunately I still can't get the context into the pipe. No matter if I call it globally or include it in Current example for
Here I get the context and can read out the user:
But this is not possible via the pipe:
Package versions used:
|
@kamilmysliwiec Is there any news on the issue / feature? Is something planned in this direction? |
@jmcdo29
therefore, the request-scoped service may be created more than once. It seems to be able to use the same instance used in request scope with:
|
I don't know if this is still relevant or especially smart but here is what I did:
import {ContextIdFactory, ModuleRef} from '@nestjs/core';
import { Plugin } from '@nestjs/apollo';
import {REQUEST_CONTEXT_ID} from '@nestjs/core/router/request/request-constants';
@Plugin()
export class LoggerPlugin {
constructor(
private readonly moduleRef: ModuleRef,
) {}
async requestDidStart(requestContext) {
if (!requestContext.context.req[REQUEST_CONTEXT_ID]) {
const newContextId = ContextIdFactory.create();
Object.defineProperty(requestContext.context.req, REQUEST_CONTEXT_ID, {
value: newContextId,
enumerable: false,
configurable: false,
writable: false,
});
// Here, I bind the request object so it can be accessed in services using @Inject(REQUEST)
this.moduleRef.registerRequestByContextId(requestContext.context.req, newContextId);
}
return {};
}
}
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { LOGGER } from '../constants';
import { Logger } from 'winston';
import { GqlContextType, GqlExecutionContext } from '@nestjs/graphql';
import { ContextIdFactory, ModuleRef } from '@nestjs/core';
@Injectable()
export class ErrorInterceptor implements NestInterceptor {
constructor(
private readonly moduleRef: ModuleRef,
) {}
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
// Getting the request object
const req = this.getRequest(context);
// The contextId should be set on the request by now
const contextId = ContextIdFactory.getByRequest(req);
const logger = await this.moduleRef.resolve<string, Logger>(LOGGER.PROVIDERS.REQUEST_LOGGER, contextId);
return next.handle().pipe(
catchError((err) => {
logger.error(err);
return throwError(err);
}),
);
}
getRequest(context: ExecutionContext) {
if (context.getType<GqlContextType>() === 'graphql') {
// do something that is only important in the context of GraphQL requests
const gql = GqlExecutionContext.create(context);
return gql.getContext().req;
}
return context.switchToHttp().getRequest();
}
} It seems to work for my usecase PS: Well, it does not work very well either, I get some |
This will be finally fixed as part of the next release #2636 |
…QL context This wasn't possible at the time. Since then nestjs/graphql#325 has been resolved & released in v11.0.0
…QL context This wasn't possible at the time. Since then nestjs/graphql#325 has been resolved & released in v11.0.0
…QL context This wasn't possible at the time. Since then nestjs/graphql#325 has been resolved & released in v11.0.0
I'm submitting a...
Current behavior
The
transform
method of global pipes is not called.Expected behavior
The
transform
method of global pipes should be called before calling a resolver method.Minimal reproduction of the problem with instructions
core.module.ts
check-input.pipe.ts
Console log does not occur.
To test this, you can use the following repository:
https://github.com/yostools/nest-example
If everything would work, the console log
Current context
should appear.What is the motivation / use case for changing the behavior?
I would like to use a global pipe that compares the input with the rights of the current user and only passes on the inputs to which the user has authorization.
check-input.pipe.ts
Environment
The text was updated successfully, but these errors were encountered: