Relay: What format data does connection expect? Errors everywhere

Created on 31 May 2016  Â·  8Comments  Â·  Source: facebook/relay

I picked up relay-stater-kit few weeks ago. Everything works perfectly with default mock data but as soon as the database comes in, it breaks.

This is the relevant part of the code. Everything is very basic and pretty much the default. It has only two types and a single connection.

// User type
const userType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
      id: globalIdField('User'),
      email: { type: GraphQLString },
      posts: {
        type: postConnection,
        args: connectionArgs,

        // getUserPosts() function should get all the posts, see it below
        resolve: (user, args) => connectionFromArray(getUserPosts(user.id), args),
      },
  }),
  interfaces: [nodeInterface],
})

// Post type
const postType = new GraphQLObjectType({
  name: 'Post',
  fields: () => ({
    id: globalIdField('Post'),
    title: { type: GraphQLString },
    content: { type: GraphQLString },
  }),
  interfaces: [nodeInterface],
})

// Connection
const {connectionType: postConnection} =
  connectionDefinitions({name: 'Post', nodeType: postType})

Im using MongoDB and Mongoose.

First thing I tried:

exports.getUserPosts = (userid) => {
    Post.find({author: userid}).exec( function (err, post) {
        if (err) return console.error(err)
        return post
    })
}

Returned format (_console.log_) is similar to this:

{ __v: 0,
  written: Sat May 21 2016 04:38:55 GMT+0300 (FLE Daylight Time),
  author: 573fbc2e119b66344d877044,
  content: 'My first post.',
  title: 'First',
  _id: 573fbc2f119b66344d877045 },{ __v: 0,
  author: 573fbc2e119b66344d877044,
  content: 'My second post',
  title: 'Second',
  _id: 574da122e90859584ca2b429 }

Warning in browser console:

Server request for query `App` failed for the following reasons:
1. Cannot read property 'length' of undefined
     _posts40BFVD:posts(first:10) {
     ^^^

Or the following error in GraphiQL:

"errors": [
    {
      "message": "Cannot read property 'length' of undefined",
      "locations": [
        {
          "line": 7,
          "column": 5
        }
      ]
    }
]

Second thing I tried:

// Mongoose query on other file
exports.getUserPosts = (userid) => {
  return new Promise((resolve, reject) => {
    Post.find({'author': userid}).exec((err, res) => {
      err ? reject(err) : resolve(res)
    })
  })
}

Returned format (_console.log_) is similar to this:

[object Object],[object Object]

This is the exact same format (obviously different keys-values) as starter kit mock data returns.

Warning in browser console:

Server request for query `App` failed for the following reasons:
1. arraySlice.slice is not a function
     _posts40BFVD:posts(first:10) {
     ^^^

Error in GraphiQL:

  "errors": [
    {
      "message": "arraySlice.slice is not a function",
      "locations": [
        {
          "line": 7,
          "column": 5
        }
      ]
    }
  ]

Unfortunately there's no errors to track (or Im just too green to find any) and I couldn't find any more information about the problem. I've spent 2 days on this, what am I missing? What does it expect?

Most helpful comment

graphql-relay provides a connectionFromPromisedArray function which waits until the promise resolves. resolve: (user, args) => connectionFromPromisedArray(getUserPosts(user.id), args), which probably is the most recommended/easiest way when dealing with promised connections.

All 8 comments

Thanks for your question!

We want to make sure to keep signal strong in the GitHub issue tracker – to make sure that it remains the best place to track issues that affect the development of Relay.

Questions like yours deserve a purpose-built Q&A forum. Would you like to post this question to Stack Overflow with the tag #relayjs? We'll be happy to answer there. Be sure to mention what database ORM you're using (ie. what provides the lean() and find() functions?). Post a link to your Stack Overflow question here, to so that we don't lose track of it.

https://stackoverflow.com/questions/ask?tags=relayjs

@unirey, you spent so much effort to write this issue...
I can not pass by without helping to you ;)

minor problem

exports.getUserPosts = (userid) => {
  return new Promise((resolve, reject) => {
    Post.find({'author': userid}).exec((err, res) => {
      err ? reject(err) : resolve(res)
    })
  })
}

find(...).exec() returns promise if u call it without callback. [http://mongoosejs.com/docs/promises.html]

So you wrapping is redundant. Use such way:

exports.getUserPosts = (userid) => Post.find({'author': userid}).exec();

Right now I'm using without exec, but it think it may be problems with mongod errors:

exports.getUserPosts = (userid) => Post.find({'author': userid});

major problem

resolve: (user, args) => connectionFromArray(getUserPosts(user.id), args),

connectionFromArray waits, that will be provided array in the first argument, not promise.

so try this

resolve: (user, args) => getUserPosts(user.id).then(arr => connectionFromArray(arr, args)),

u wait when getUserPosts promise resolves, in then get result (array) from this promise and pass it to connectionFromArray.

I think it should work after this changes.

use async await

resolve: async(user, args, { tokenData } ) => connectionFromArray( await getUserPosts(user.id), args);

graphql-relay provides a connectionFromPromisedArray function which waits until the promise resolves. resolve: (user, args) => connectionFromPromisedArray(getUserPosts(user.id), args), which probably is the most recommended/easiest way when dealing with promised connections.

Ooh, yes. These are exactly the answers that I was hoping to give… on Stack Overflow. Can we get this question/answer series up there? That way, the answers can live on to help others, rather than languishing in a closed GitHub issue.

@nodkz, @steveluscher, @edvinerikson, @alexhawkins Thank you for your suggestions!

I asked this question in SO, you can find it here. Im sorry for trashing the issue tracker, I just didn't know where to go after messing with this for several days. It's sometimes tricky to get answer for Relay because there aren't that many users yet. But I know better next time.

Feel free to provide your own answer and it would be awesome if you explained pros and cons that your suggestion has (if it has) with few sentences or if there's a suggested way to do this with Relay and Node.

The current answer to my question in SO was very eye-opening, I spent whole day in YT watching videos and reading articles - I finally discovered and wrapped my head around async JavaScript.

Upvoted. This makes me so happy. Thanks everyone!

…although I'd love to see @edvinerikson's answer up there too :)

Was this page helpful?
0 / 5 - 0 ratings