hayes / pothos

Pothos GraphQL is library for creating GraphQL schemas in typescript using a strongly typed code first approach
https://pothos-graphql.dev
ISC License
2.33k stars 159 forks source link

unsubscribe function for subscriptionField #450

Open boenni23 opened 2 years ago

boenni23 commented 2 years ago

I want to implement my own subscription manager. I can't use the plugin because I need a different API. How do I know if a subscription was ended / lost?

I need something like this:

builder.subscriptionField('station', (t) =>
  t.field({
    args: {
      where: t.arg({
        type: "StationWhereInput"
      })
    },
    type: 'StationSubscriptionPayload',
    subscribe: (_parent: any, args: any, context: any, { fieldName }: ResolveShape) => {
      const channel = uid()
      SUBSCRIPTIONS[channel] = { ...args, channelName: fieldName }
      return pubsub.subscribe(channel)
    },
    unsubscribe: ???,
    resolve: async ({ node, mutation }) => {
      return {
        mutation,
        node
      }
    }
  })
)

I need to track active Subscriptions and want to know when someone stopped a subscription. (remove it from my SUBSCRIPTIONS object).

Or if this is not possible, is there something like apollo's withFilter? That would be even cooler. https://www.apollographql.com/docs/apollo-server/data/subscriptions/#filtering-events

boenni23 commented 2 years ago

I found a workaround for all interested. The socket can be found in the context variable. { req: { socket: Socket } } = context You can now listen for the close event.

  socket.addListener('close', () => {
    delete SUBSCRIPTIONS[channel]
  })
hayes commented 2 years ago

I think this is mostly a documentation issue. Subscriptions in graphql are a little weird, and are driven through async-iterators in the core graphql package.

I'll try to find some time to improve the documentation around this, because it's not very straight forward. Listening to the socket closing is probably okay, but ideally I think using the return() feature of the subscription async iterator is probably a more correct solution.

Examples integrating with existing solutions would probably also be helpful.

You can see an example of an async iterator with a return callback here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_async_iterables