Search code examples
typescriptgraphqlapollo-servergraphql-subscriptionsasync-iterator

How do you map PubSub value of a GraphQL subscription in Apollo?


I'm making a GraphQL backend in Apollo, and I'd like to use subscriptions. I followed Apollo's docs, and I've gotten basic subscriptions working using graphql-subscriptions. This package also comes with filtering via the built-in withFilter function. However, I don't want to emit all of the data published via PubSub because some of this data is used for filtering purposes only.

Ex.

// GraphQL Schema
type Subscription {
  mySubscription(filter: MySubscriptionFilter!): ID!
}
// Publishing the event
pubsub.publish("MY_SUBSCRIPTION", { id: "2092330", username: "asdf", roles: [ "USER", "MODERATOR" ] });

// Handling the event for a subscription
const resolvers = {
  Subscriptions: {
    mySubscription: {
      subscribe: withFilter(
        () => pubsub.asyncIterator("MY_SUBSCRIPTION"),
        (payload, variables) => {
          return customFiltering(payload, variables);
        }
      )
    }
  }
}

This returns an object with the type: { id, username, roles }. However, the username and roles fields are only used for filtering. I ultimately need to return an object of type { mySubscription: id }, because that's what my GraphQL schema says.

Is there a way to do something like this?

// Handling the event for a subscription
const resolvers = {
  Subscriptions: {
    mySubscription: {
      subscribe: withFilter(
        () => pubsub.asyncIterator("MY_SUBSCRIPTION"),
        (payload, variables) => {
          return customFiltering(payload, variables);
        }
      ).map(x => {
        return { mySubsription: x.id }
      }) // Map function where x is the payload from the pubsub
    }
  }
}

Solution

  • Whoops, it looks like I overlooked the resolve function in a subscription.

    From the graphql-subscriptions github page

    Payload Manipulation

    You can also manipulate the published payload, by adding resolve methods to your subscription:

    const SOMETHING_UPDATED = 'something_updated';
    
    export const resolvers = {
      Subscription: {
        somethingChanged: {
          resolve: (payload, args, context, info) => {
            // Manipulate and return the new value
            return payload.somethingChanged;
          },
          subscribe: () => pubsub.asyncIterator(SOMETHING_UPDATED),
        },
      },
    }