Reputation: 934
I have a Nest.js app with a REST module and a GraphQL module. Both are imported into an App.module.ts
. I'm using Nest's Throttler Guard to protect the whole application. As it's already known, GraphQL does not work with the normal ThrottlerGuard
, so I created a GqlThrottlerGuard
and imported it on the GraphQL module, while importing the original ThrottlerGuard
on the REST module.
So, my graphQL module looks like this:
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true
}),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('security.throttle.ttl'),
limit: config.get('security.throttle.limit'),
}),
}),
],
providers: [
{
provide: APP_GUARD,
useClass: GqlThrottlerGuard,
},
],
})
export class GraphModule { }
And the REST module, like this:
@Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('security.throttle.ttl'),
limit: config.get('security.throttle.limit'),
}),
}),
],
controllers: [RestController],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class RestModule implements NestModule {}
Finally, both modules are imported to the App Module, which is the module I actually run:
@Module({
imports: [
RestModule,
GraphModule,
],
})
export class AppModule { }
For some reason, the error seen here is still happening to me on the GraphModule
, even though the normal ThrottlerGuard
is imported only on the RestModule. Should it work like this? How can I solve it?
Upvotes: 2
Views: 2791
Reputation: 70412
APP_GUARD
is a global binding, it applies to all routes. You should make one coherent guard that returns the proper request response based on the ExecutionContext#getType
method which will either return http
or graphql
@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext) {
const reqType = context.getType<ContextType | 'graphql'>()
if (reqType === 'graphql') {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.res };
} else if (reqType === 'http') {
return {
req: context.switchToHttp().getRequest(),
res: context.switchToHttp().getResponse()
}
} else {
// handle rpc and ws if you have them, otherwise ignore and make previous `else if` just an `else`
}
}
Upvotes: 5