Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Subscriptions with Nested connected data returns [Object Object] #306

Closed
MoonTahoe opened this issue Dec 1, 2017 · 5 comments
Closed

Subscriptions with Nested connected data returns [Object Object] #306

MoonTahoe opened this issue Dec 1, 2017 · 5 comments

Comments

@MoonTahoe
Copy link

I discovered this issue when reviewing the chapter on subscriptions on the How to GraphQL website.

The sample and example works, but If you try to subscribe to connected data you get [Object object] in Graphiql.

In the lesson, the following Subscription type is created:

type Subscription {
  Link(filter: LinkSubscriptionFilter): LinkSubscriptionPayload
}

input LinkSubscriptionFilter {
  mutation_in: [_ModelMutationType!]
}

type LinkSubscriptionPayload {
  mutation: _ModelMutationType!
  node: Link
}

enum _ModelMutationType {
  CREATED
  UPDATED
  DELETED
}

And in the Subscription resolver pubsub is setup...

Subscription: {
  Link: {
    subscribe: () => pubsub.asyncIterator('Link'),
  },
},

And in the create link Resolver a Link event is published

Mutation: {
  createLink: async (root, data, {mongo: {Links}, user}) => {
    assertValidLink(data);
    const newLink = Object.assign({postedById: user && user._id}, data)
    const response = await Links.insert(newLink);

    newLink.id = response.insertedIds[0]
    pubsub.publish('Link', {Link: {mutation: 'CREATED', node: newLink}});

    return newLink;
  },
},

So far everything works: in fact if I add the subscription to Graphiql it all works...

subscription {
  Link(filter:{
    mutation_in: [CREATED]
  }) {
    mutation
    node {
      id
      url
      description
    }
  }
}

The Issue...

occurs when I try to request nested link data. In a typical query for allLinks I can connect users through the postedBy resolver. However, in the subscription trying to see the postedBy user info causes the subscription response to break.

Intended Outcome: the connected user's data is returned in the subscription.

Actual Outcome: [Object, object] is returned by graphiql

Subscription that causes the problem:

subscription {
  Link(filter:{
    mutation_in: [CREATED]
  }) {
    mutation
    node {
      id
      url
      description
      postedBy {
          name
      }
    }
  }
}

I noticed that that when a subscription is published the Link resolvers that find the postedBy connection are not invoked:

Link: {
        id: root => root._id || root.id,
        postedBy: async ({postedById}, data, {mongo: {Users}}) => {
            return await Users.findOne({ _id: postedById })
        }
    },

I've tried adding code to find the user directly to the mutation, but the subscription still returns [Object Object]

        createLink: async (root, data, {mongo: {Links, Users}, user}) => {
            assertValidLink(data)
            const newLink = Object.assign({ postedById: user && user._id }, data)
            const response = await Links.insert(newLink)
            newLink.id = response.insertedIds[0]
            newLink.postedBy = await Users.findOne({ _id: user._id })
            newLink.postedBy.id = newLink.postedBy._id
            pubsub.publish('Link', { 
                "Link": {
                    mutation: 'CREATED', 
                    node: newLink
                } 
            })
            return newLink
        },

When I use pubsub.publish... how can I make nested resolvers work with subscriptions.

@nharraud
Copy link

nharraud commented Dec 2, 2017

Same issue for me, with the same tutorial.
The [Object object] message seems to be a Graphiql bug. See graphql/graphiql#636

The actual content returned via websocket is:
error

This is for the query:

subscription {
  Link(filter:{mutation_in:[CREATED]}) {
    node {
      url
      description
      postedBy {
        id
        name
      }
    }
  }
}

I think this issue is similar to #236

There is no dataloader as I wanted to make sure that it wasn't the origin of the issue.

@nharraud
Copy link

nharraud commented Dec 2, 2017

After some more digging it turns out that the problem comes from the empty context passed on subscriptions.
@MoonTahoe You can just add the context in the onOperation parameter of the SubscriptionServer.create:

        SubscriptionServer.create(
            {
               execute, subscribe, schema,
               onOperation: (message, params, webSocket) => {
                return { ...params, context: {mongo} }
              },
            },
            { server, path: '/subscriptions' },
        );

Note that I am not passing the user here. You can add it to the context too. (This is specific to the tutorial @MoonTahoe and me have been following)
This issue is related to #300

@MoonTahoe
Copy link
Author

@nharraud, thanks! it works! That took care of it.

For reference, in case anyone is making this change in the lesson...

  1. I had to use Object.assign, the lesson does not setup babel.
  2. I had to pass 'dataloaders', in the lesson we added dataloaders to the context alongside of mongo. You have to do the same with subscriptions
Object.assign(
  params, 
  {
    context: {
       mongo, 
       dataloaders: buildDataloaders(mongo)
    }
  })

@lebedev
Copy link

lebedev commented Dec 5, 2017

in case anyone is making this change in the lesson

@MoonTahoe, I think it would be better if you create an issue in howtographql/howtographql repo about this.

And, actually, I did the same thing when I was studying that tutorial too. 👍

Also, this issue can be closed, I believe.

@MoonTahoe
Copy link
Author

Yea, thanks. I've seen this happen before so I originally though it may be a transport issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants