Let's say I have a Post and Comment model. A Post hasMany Comments. In React Apollo I'm using subscribeToMore on a Query for a particular post.
The query appears as follows:
query getPost(id: ID!){
id, title, comments { id }
}
And the subscription which returns the post with any new comments:
subscription commentAdded(postId: ID!){
id, title, comments { id }
}
The query works. It returns all of the associated Comments, which I can then render as in list on the page.
Yet when using the subscribeToMore helper for the query, I get the follow error whenever the event subscription is dispatched.
Cannot read property 'Comment' of undefined.
The strange thing is that if I remove the Comment, such that the subscription looks like...
subscription commentAdded(postId: ID!){
id, title
}
...it works perfectly. I'm confused why it seems to treat the Comments as associating with an undefined model.
This isn't just a Comments -> Posts issue, this happens on any model that tries to return a subscription with an association.
post query:
post: async (parent, {id}, {models}) => {
return await models.Post.findByPk(id);
}
saveComment resolver:
saveComment: async (parent, {postId, comment}, {models, me}) => {
let post = await models.Post.findByPk(postId);
let comment = await models.Comment.create({comment, postId});
await pubsub.publish("COMMENT_CREATED", {
commentCreated: post,
postId
})
}
commentCreated subscription:
commentCreated: {
subscribe: withFilter(
() => pubsub.asyncIterator(["COMMENT_CREATED"]),
(payload, variables) => {
return payload.postId == variables.postId
}
)
}
Post type resolver
Post: {
comments: async (post, args, {models}) => {
return await models.Comment.findAll({where:{postId: post.id}});
}
}
Server initialization:
const server = new ApolloServer({
typeDefs: schema,
resolvers,
subscriptions: {
onConnect: (connectionParams, webSocket) => {
return true
},
},
context: async ({ req, connection }) => {
if(connection){
return connection.context;
}else{
const me = await getMe(req);
return {
models,
me,
secret: process.env.SECRET,
};
}
}
});
Your context
function only returns connection.context
, which will not include any of the custom properties you want to include (me
, models
, etc.). Doing something like this should fix the problem:
context: async ({ req, connection }) => {
const context = {
models,
secret: process.env.SECRET,
};
if(connection){
return { ...connection.context, ...context };
} else {
const me = await getMe(req);
return { ...context, me };
}
}