apollographql / graphql-subscriptions

:newspaper: A small module that implements GraphQL subscriptions for Node.js
MIT License
1.58k stars 133 forks source link

Using pubsub in onConnect and onDisconnect #247

Closed merpig closed 2 years ago

merpig commented 2 years ago

I've done a good bit of research on using pubsub in the SubscriptionServer onConnect and onDisconnect methods and haven't found any ways to do this or work arounds. I'm wanting to publish events to other clients when subscriptions open/close with a specific client.

Example of what I would like to be able to do

const subscriptionServer = SubscriptionServer.create({
  schema,
  context: authMiddleware,
  execute,
  subscribe,
  onConnect(connectionParams) {
    const token = connectionParams.authToken.split(' ').pop().trim();
    if(token){
      try {
        const { data } = jwt.verify(token, secret, { maxAge: expiration });
        console.log(`${data.username} has connected`);

        // I would like to publish this event to the subscriptions in my resolvers
        pubsub.publish('USER_CONNECTED', {/* data to be passed */});
        return data
      } catch {
        console.log('Invalid token');
      }
    }
    return false;
  },
  onDisconnect(_,context){
    context.initPromise.then( async user=>{
      if(user){
        console.log(`${user.username} has disconnected`)

        // I would like to publish this event to the subscriptions in my resolvers
        pubsub.publish('USER_DISCONNECTED', {/* data to be passed */});
      }
    })
  }
}, {
  server: httpServer,
  path: server.graphqlPath
});

My resolvers look like:

const resolvers = {
  Query: {...},
  Mutation: {...},
  Subscription: {
    loggedIn: {
      subscribe: withFilter(
        ()=> pubsub.asyncIterator('USER_CONNECTED'),
        ({data},_,context)=> {
          return data.includes(context.username)
        }
      )
    },
    loggedOut: {
      subscribe: withFilter(
        ()=> pubsub.asyncIterator('USER_DISCONNECTED'),
        ({data},_,context)=> {
          return data.includes(context.username)
        }
      )
    }
  }
}