1

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,
            };
        }
    }
});
Nathanael
  • 954
  • 3
  • 19
  • 39
  • Please edit your question to include the relevant resolvers. – Daniel Rearden Sep 08 '19 at 23:28
  • Edited. It's strange because the subscription works, insomuch as it contains the initial model, however the associations won't work. And I know the associations are typed correctly, as they work in the query. It appears to be something pertaining to the subscription settings specifically, but I'm unsure. – Nathanael Sep 09 '19 at 01:27
  • I can set it up so that it can trigger new query each time the response data is added, which works, but it's an annoying work around for something that should be pretty simple. – Nathanael Sep 09 '19 at 01:31
  • So this sounds like an issue with your `context` function. Context with subscriptions [is a bit wonky](https://github.com/apollographql/apollo-server/issues/1597). Can you include that as well? – Daniel Rearden Sep 09 '19 at 02:55

1 Answers1

1

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 };
  }
}
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183