Cannot read property 'after' of undefined in implementing react-relay
Asked Answered
H

2

1

In my nodejs application

here is my schema.js file

import {
  GraphQLBoolean,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} from 'graphql';

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  connectionFromPromisedArray,
  cursorForObjectInConnection,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
  toGlobalId,
} from 'graphql-relay';

import {
  User,
  getUser,
  getPosts,
  createpost,
} from '../data/database.js';

var { nodeInterface, nodeField } = nodeDefinitions(
  (globalId) => {
    var { type, id } = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    }else if (type === 'Post') {
      return getPosts(id);
    }
    return null;
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    }else if (obj instanceof Post) {
      return postType;
    }
    return null;
  }
);

var userProfileImageType = new GraphQLObjectType({
  name: 'ProfileImage',
  fields: {
    full: {
      type: GraphQLString
    }
  }
});

var userLocalAccountType = new GraphQLObjectType({
  name: 'Local',
  fields: {
    email: {
      type: GraphQLString
    }
  }
});

var userFacebookAccountType = new GraphQLObjectType({
  name: 'Facebook',
  fields: {
    id: {
      type: GraphQLString
    },
    displayName: {
      type: GraphQLString
    }
  }
});

var userGoogleAccountType = new GraphQLObjectType({
  name: 'Google',
  fields: {
    id: {
      type: GraphQLString
    },
    displayName: {
      type: GraphQLString
    }
  }
});

var postType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    id: globalIdField('Post'),
    title: {
      type: GraphQLString
    },
    userId: globalIdField('User'),
    content: {
      type: GraphQLString
    }
  },
  interfaces: [nodeInterface]
});

/**
 * Define your own connection types here
 */

const {
  connectionType: postConnection,
  edgeType: postEdge,
} = connectionDefinitions({name: 'Post', nodeType: postType});

let createPostMutation = mutationWithClientMutationId({
    name: 'CreatePost',

    inputFields: {
      title: { type: new GraphQLNonNull(GraphQLString) },
      content: { type: new GraphQLNonNull(GraphQLString) },
      userId: { type: new GraphQLNonNull(GraphQLString) },
    },

    outputFields: {
      postEdge: {
        type: postConnection,
        resolve: (obj) => ({ node: obj, cursor: obj.insertedId })
      },
    },

    mutateAndGetPayload: ({title, content,userId}) => {
      console.log({title, content,userId})
      return createpost({title, content,userId})
    }
  });

var userType = new GraphQLObjectType({
  name: 'User',
  fields: {
    id: globalIdField('User'),
    fullName: {
      type: GraphQLString,
      description: "Users' Full Name"
    },
    isPremium: {
      type: GraphQLBoolean,
      description: "Does the user have premium subscription?"
    },
    currentPostCount: {
      type: GraphQLInt,
      description: "User's current total post"
    },
    images: {
      type: userProfileImageType,
      description: "User's profile image links"
    },
    local: {
      type: userLocalAccountType,
      description: "User's local account info"
    },
    facebook: {
      type: userFacebookAccountType,
      description: "User's Facebook account info"
    },
    google: {
      type: userGoogleAccountType,
      description: "User's Google Plus account info"
    },
    posts: {
      type: postConnection,
      args: {
        ...connectionArgs,
        query: { type: GraphQLString }
      },
      resolve: (rootValue) => {
        return connectionFromPromisedArray(getPosts(rootValue))
      }
    },
  },
  interfaces: [nodeInterface]
});

var Root = new GraphQLObjectType({
  name: 'Root',
  fields: () => ({
    user: {
      type: userType,
      resolve: (rootValue, _) => {
        return getUser(rootValue)
      }
    },
  })
})

export var schema = new GraphQLSchema({
  query: Root,
  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: () => ({
      createPost: createPostMutation
    })
  })
});

and below is my database.js

import User from './models/userModel'
import Post from './models/postModel'

export { User }
export { Post }

export function getUser(user) {
  let validUser = false
  if (user.local || user.facebook || user.google) {
    validUser = true
  }
  return new Promise((resolve, reject) => {
    if (validUser) {
      let localEmail = user.local.email || ""
      let googleID = user.google.id || ""
      let facebookID = user.facebook.id || ""
      User.findOne({
        $or: [
          { "local.email": localEmail },
          { "facebook.id": facebookID },
          { "google.id": googleID }
        ]
      }, function(err, existingUser) {
        if (err || !existingUser) {
          resolve({})
        } else {
          resolve(existingUser)
        }
      });
    } else {
      resolve({})
    }
  })
}

export function getPosts(user) {
  return new Promise((resolve, reject) => {
     Post.find({}).exec({}, function(err, posts) {
        resolve(posts)
      });

  })
}

export function createpost({title, content,userId}){
  return new Promise((resolve, reject) => {
      const blogPostModel = new Post({title, content,userId});
      const newBlogPost = blogPostModel.save();
      if (!newBlogPost) {
        throw new Error('Error adding new blog post');
      }
       resolve({})
  })
}

I am getting user by

Relay.QL `query { user}`

I want to fetch all posts along with user

Relay.QL 'query{
  user {
    id,
    posts(first: 3) {
      edges {
        node {
          id,
          title
        }
      }
    }
  }
}'

but i am getting below error in terminal

    Failed to execute query `UserQueries` for the following reasons:

1. Cannot read property 'after' of undefined
   le {id,displayName},_posts3KBCho:posts(first:3) {edges {node

Please help. Thanks in Advance.

Honniball answered 23/7, 2016 at 10:31 Comment(0)
Y
0

Update #1:

The problem is in the implementation of posts field in userType definition.

posts: {
  type: postConnection,
  args: {
    ...connectionArgs,
    query: { type: GraphQLString }
  },
  resolve: (rootValue) => {
    return connectionFromPromisedArray(getPosts(rootValue))
  }
},

While destructuring args, the Rest parameter connectionArgs should come in the end. query should come first. Because of the wrong use of rest parameters, connectionArgs is found undefined.

By the way, you don't pass query for posts. If you don't provide query argument, you should just use args: {...connectionArgs},.


Looks like you've used Mongoose library. If that's the case, one obvious problem is in the implementation of getPosts function. exec itself returns a promise. So, it doesn't need to be wrapped in a Promise. Replace this

export function getPosts(user) {
  return new Promise((resolve, reject) => {
     Post.find({}).exec({}, function(err, posts) {
        resolve(posts)
      });

  })
}

with this

export function getPosts(user) {
    return Post.find({user_id: user._id}).exec();
}

Please let me know if you face further problems after fixing this.

Yurev answered 23/7, 2016 at 12:13 Comment(5)
Thanks for reply. But I tried that already also I console log getPosts() and I am getting posts list their. still same error is coming . 1. Cannot read property 'after' of undefined – flag or sometimes getting error.... Cannot return null for non-nullable field PostConnection.pageInfo. le,content},cursor},pageInfo {hasNextPage,hasPreviousPage}}}Honniball
You didn't import Post in your schema.js file. What happens after you import Post?Yurev
It doesn't makes any difference as getposts is importing from database.js and POST is imported .Joerg
@Honniball I identified a problem in your implementation of posts field in userType. Please see my update. It should solve the issue.Yurev
@Joerg For OP's immediate problem, it does not matter. But while doing node root call, obj instanceof Post in node definitions will cause problem. Post type is not imported.Yurev
Q
2

Made the same mistake today and it took me little bit to find right solution. I looked at your question with same issue, but didn't resolved my problem. After some time I've noticed I'm missing args in my connectionFromPromisedArray call. So to fix your issue try changing this:

posts: {
      type: postConnection,
      args: {
        ...connectionArgs,
        query: { type: GraphQLString }
      },
      resolve: (rootValue, args) => { // <== here is added args attribute
        return connectionFromPromisedArray(getPosts(rootValue), args) // <== here is added args attribute
      }
    },
Quintilla answered 13/12, 2016 at 6:52 Comment(0)
Y
0

Update #1:

The problem is in the implementation of posts field in userType definition.

posts: {
  type: postConnection,
  args: {
    ...connectionArgs,
    query: { type: GraphQLString }
  },
  resolve: (rootValue) => {
    return connectionFromPromisedArray(getPosts(rootValue))
  }
},

While destructuring args, the Rest parameter connectionArgs should come in the end. query should come first. Because of the wrong use of rest parameters, connectionArgs is found undefined.

By the way, you don't pass query for posts. If you don't provide query argument, you should just use args: {...connectionArgs},.


Looks like you've used Mongoose library. If that's the case, one obvious problem is in the implementation of getPosts function. exec itself returns a promise. So, it doesn't need to be wrapped in a Promise. Replace this

export function getPosts(user) {
  return new Promise((resolve, reject) => {
     Post.find({}).exec({}, function(err, posts) {
        resolve(posts)
      });

  })
}

with this

export function getPosts(user) {
    return Post.find({user_id: user._id}).exec();
}

Please let me know if you face further problems after fixing this.

Yurev answered 23/7, 2016 at 12:13 Comment(5)
Thanks for reply. But I tried that already also I console log getPosts() and I am getting posts list their. still same error is coming . 1. Cannot read property 'after' of undefined – flag or sometimes getting error.... Cannot return null for non-nullable field PostConnection.pageInfo. le,content},cursor},pageInfo {hasNextPage,hasPreviousPage}}}Honniball
You didn't import Post in your schema.js file. What happens after you import Post?Yurev
It doesn't makes any difference as getposts is importing from database.js and POST is imported .Joerg
@Honniball I identified a problem in your implementation of posts field in userType. Please see my update. It should solve the issue.Yurev
@Joerg For OP's immediate problem, it does not matter. But while doing node root call, obj instanceof Post in node definitions will cause problem. Post type is not imported.Yurev

© 2022 - 2024 — McMap. All rights reserved.