Skip to content
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

No documentation on how to use GqlThrottlerGuard with Subscription #1110

Open
1 task done
vytautas-pranskunas- opened this issue Aug 18, 2022 · 8 comments
Open
1 task done

Comments

@vytautas-pranskunas-
Copy link

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

I am using global throttler guard for my graphql api. But I get an error when I am adding subscriptions
"Cannot read properties of undefined (reading 'ip')",
It is thrown bu GqlThrottlerGuard

Describe the solution you'd like

It would be great to have section in documentation here: https://docs.nestjs.com/security/rate-limiting#graphql how to handle it. I had to dig into your github code to see that there is a @SkipThrottle() decorator

Teachability, documentation, adoption, migration strategy

No response

What is the motivation / use case for changing the behavior?


@jmcdo29
Copy link
Member

jmcdo29 commented Aug 18, 2022

GraphQL Subscriptions, like general websockets, act a little bit differently. Can you get me a reproduction with subscriptions enabled and I can work on the documentation of how to make it work with the throttler?

@vytautas-pranskunas-
Copy link
Author

vytautas-pranskunas- commented Aug 18, 2022

@jmcdo29 it is just a matter of @SkipThrottle() - which I have found by diging into your repo code or you can make something else for people who wish to Throttle subscription messages :)

Unfurtunutelly i have no time at this moment f time to build repro code. But it is a matter of 1 resolver and GQL module from Nest.JS.

I can drop you some code that might speed your repro:

@Module({
    imports: [
        ThrottlerModule.forRoot({
            ttl: 60,
            limit: 60,
        }),
        GraphQLModule.forRootAsync<ApolloDriverConfig>({
            driver: ApolloDriver,
            useFactory: () => ({
                playground: false,
                autoSchemaFile: 'schema.gql',
                installSubscriptionHandlers: true,
                plugins: [ApolloServerPluginLandingPageLocalDefault()],
                subscriptions: {
                    'subscriptions-transport-ws': true
                    
                },
                formatError(error: GraphQLError) { return exceptionFormatter(error); },
                context: async ({ req, res }) => {

                    return {
                      
                    };
                },
            }),
        }),
        
    ],
    providers: [
       
        {
            provide: APP_GUARD,
            useExisting: GqlThrottlerGuard,
        },
      
        GqlThrottlerGuard,
        
    ]
})
export class AppModule {
   
}

and

@Public()
// @SkipThrottle()
@Resolver()
export class SubscriptionsResolver {
    constructor(@Inject('PUB_SUB') private pubSub: PubSub) { }

    @Subscription(() => NotificationResponse)
    notification(
        @Root() notificationPayload: NotificationPayload,
        @Args() args: NotificationsSubscriptionArgs,
    ) {
        return this.pubSub.asyncIterator(SubscriptionTopic.notifications);
    }
}

@aliabbasrizvi
Copy link

I am running into a similar issue where all Query, Mutation operations are fine but the GqlThrottlerGuard throws Cannot read property 'header' of undefined error for GraphqQL subscription. Do I need to be doing something different? Or is skipping the only option at the moment?

@jmcdo29
Copy link
Member

jmcdo29 commented Oct 26, 2022

@aliabbasrizvi you'd need to find a reliable way to allow for writing headers of the websocket. The error comes from around here. If you can get a reproduction I can probably find something to use here

@hhphuc12
Copy link

hhphuc12 commented Dec 24, 2022

For those who are facing the issue like @aliabbasrizvi, you just need to put context: ({ req, res }) => ({ req, res }) into your GraphQLModule configuration!

@jirios125
Copy link
Contributor

For those who are facing the issue like @aliabbasrizvi, you just need to put context: ({ req, res }) => ({ req, res }) into your GraphQLModule configuration!

Simply adding this to the GraphQLModule configuration works, maybe this should be added to the ReadMe and this problem should be closed @jmcdo29 :)

@bellondr
Copy link

@jmcdo29 any update?
Still do not know how to use GqlThrottlerGuard with Subscription.
When use

@Injectable()
export class WsThrottlerGuard extends ThrottlerGuard {
  async handleRequest(context: ExecutionContext, limit: number, ttl: number): Promise<boolean> {
    const client = context.switchToWs().getClient();
    const ip = client._socket.remoteAddress;
    const key = this.generateKey(context, ip);
    const { totalHits } = await this.storageService.increment(key, ttl);

    if (totalHits > limit) {
      throw new ThrottlerException();
    }

    return true;
  }
}

Throw Cannot read properties of undefined (reading '_socket')
if use

@Injectable()
export class GqlThrottlerGuard extends ThrottlerGuard {
 getRequestResponse(context: ExecutionContext) {
   const gqlCtx = GqlExecutionContext.create(context);
   const ctx = gqlCtx.getContext();
   return { req: ctx.req, res: ctx.res };
 }
}

Throw error Cannot read properties of undefined (reading 'ip')

Is there an example to set GqlThrottlerGuard with subscriptions

@jmcdo29
Copy link
Member

jmcdo29 commented Oct 11, 2023

As I said, if someone can get me a reproduction I can better look into it. I haven't tried to look into rate limiting subscriptions as I don't use gql much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants