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

Internal error occurred during message handling. Please check your implementation. Error: Subscription field must return Async Iterable. Received: undefined. #405

Open
alexpchin opened this issue May 11, 2022 · 1 comment

Comments

@alexpchin
Copy link

alexpchin commented May 11, 2022

When creating a subscription resolver as follows:

const pubsub = require('@app/lib/pubSub')

module.exports = {
  name: 'findManySubscription',
  kind: 'subscription',
  type: 'Chat',
  resolve: async payload => {
    return payload.updatePost
  },
  subscribe: async () => pubsub.asyncIterator('updatePost')
}

and adding it to:

schemaComposer.Subscription.addFields({
  chatMany: ChatTC.getResolver('findManySubscription')
})

I see the error:

Internal error occurred during message handling. Please check your implementation. Error: Subscription field must return Async Iterable. Received: undefined.

However, when adding as so:

schemaComposer.Subscription.addFields({
  chatMany: {
    type: 'Chat',
    resolve: payload => {
      return payload.updatePost
    },
    subscribe: () => pubsub.asyncIterator('updatePost')
  }
})

This is fine.

For resolvers, I am adding as per:

for (const resolver in resolvers) {
  ChatTC.addResolver(resolvers[resolver])
}

Any ideas why this wouldn't be ok?

@Resousse
Copy link

Very funny, that I started to resolve the same on my own, 3 days ago!
My requirement was to leverage an existing resolver to resolve subscription.
As per the document I tried resolve: (_id) => Task.findById(_id)
Task is my mongoose model object, however, it's different of the existing mongooseResolvers.findById which I've wrapResolve to extend the working. So using directly the model instead of the compose query.

Finally, my result is :

import { getProjectionFromAST, deepmerge } from 'graphql-compose';

const TaskSubscription = {
  taskAdded: {
    type: TaskTC,
    resolve: (source, args, context, info)  =>{     
       let projection = getProjectionFromAST(info);
      return TaskQuery.taskById.resolve({ source, args:{_id : source._id.toString()}, context, info, projection })},
    subscribe: () => pubSub.asyncIterator(['TASK_ADDED']),
  }
};

const TaskMutation = {
    taskCreateOne: TaskTC.mongooseResolvers.createOne().wrapResolve(next => async rp =>  {
      const res = await next(rp);
      const _id = res?.record?._id;
      if (_id)
        pubSub.publish('TASK_ADDED', _id);
      return res;
    })};

The tricky part was:

resolve: (source, args, context, info)  =>{     
       let projection = getProjectionFromAST(info);
      return TaskQuery.taskById.resolve({ source, args:{_id : source._id.toString()}, context, info, projection })}

The second line is important to retrieve projection based of what has been sent during the Subscription {} phase.
The third line is used to exec the resolver using parameters.

I will try to propose a PR to improve documentation about this.
Let me know if it solves your problem?

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

2 participants