graphql-compose-mongoose
graphql-compose-mongoose copied to clipboard
Internal error occurred during message handling. Please check your implementation. Error: Subscription field must return Async Iterable. Received: undefined.
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?
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?