akshay akshay - 3 months ago 76
Node.js Question

Abstract type Node must resolve to an Object type at runtime for field Root.node with value \"\",received \"null\"."

I am implementing a search feature with react and relay.
Below is my schema.js

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

var postType = new GraphQLObjectType({
name: 'Post',
fields: {
_id: {
type: new GraphQLNonNull(GraphQLID)
},
createdAt: {
type: GraphQLString
},
id: globalIdField('Post'),
title: {
type: GraphQLString
},
color: {
type: GraphQLString
},
userId: globalIdField('User'),
username: {
type: GraphQLString,
resolve: (post) => getUserById(post.userId),
},
content: {
type: GraphQLString
},
images: {
type: postImageType,
description: "Post's main image links"
}
},
interfaces: [nodeInterface]
});
const {
connectionType: postConnection,
} = connectionDefinitions({name: 'Post', nodeType: postType});

var settingType = new GraphQLObjectType({
name: 'Setting',
fields: {
_id: {
type: new GraphQLNonNull(GraphQLID)
},
id: globalIdField('Setting'),
amount: {
type: GraphQLString
},
all_posts: {
type: postConnection,
args: {
...connectionArgs,
query: {type: GraphQLString}
},
resolve: (rootValue, args) => connectionFromPromisedArray(
getAllPosts(rootValue, args),
args
),
},
},
interfaces: [nodeInterface]
});

var Root = new GraphQLObjectType({
name: 'Root',
fields: () => ({
node: nodeField,
setting: {
type: settingType,
args: {
...connectionArgs,
currency: {type: GraphQLString}
},
resolve: (rootValue, args) => {
return getSetting(args.currency).then(function(data){
return data[0];
}).then(null,function(err){
return err;
});
}
},
})
});


Below is my database.js

export function getAllPosts(params,args) {
let findTitle = {};
let findContent = {};
if (args.query) {
findTitle.title = new RegExp(args.query, 'i');
findContent.content = new RegExp(args.query, 'i');
}
console.log("getAllPosts",args)
return new Promise((resolve, reject) => {
Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec({}, function(err, posts) {
if (err) {
resolve({})
} else {
resolve(posts)
}
});
})
}


Now I want to fetch all posts by $query variable
So in view I wrote like this

import React, { Component } from 'react';
import Relay from 'react-relay';

class BlogList extends Component {
constructor(props) {
super(props);
this.state = {
query: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
}

handleSubmit(){
this.props.relay.setVariables({query: this.state.query});
}
render() {
return (

<div className="input-group col-md-12">
<input type="text" onChange={this.handleChange.bind(this,"query")} value={this.state.query} name="query" placeholder="Enter Title or content"/><br/>

<span className="input-group-btn">
<button type="button" onClick={this.handleSubmit} className="btn btn-info btn-lg">
<i className="glyphicon glyphicon-search"></i>
</button>
</span>
</div>
)
}
};

export default Relay.createContainer(BlogList, {
initialVariables: {
query: ''
},
fragments: {
viewer: () => Relay.QL`
fragment on Setting {
id,
all_posts(first: 10000000,query: $query) {
edges {
node {
id,
_id,
title,
content,
createdAt,
username,
color,
images{
full
}
}
}
}
}
`,
},
});


And in routes I have

const SettingQueries = {
viewer: () => Relay.QL`query{
setting(currency: "USD")
}`,
}
export default [{
path: '/',
component: App,
queries: UserQueries,PostQueries,SettingQueries,
indexRoute: {
component: IndexBody,
},
childRoutes: [
,{
path: 'settings',
component: Setting,
queries: SettingQueries,
}]
}]


Things are working on /graphql as
Graphql UI

but when I search from website it generates error in response

{
"data": {
"node": null
},
"errors": [
{
"message": "Abstract type Node must resolve to an Object type at runtime for field Root.node with value \"\",received \"null\".",
"locations": [
{
"line": 2,
"column": 3
}
]
}
]
}


as my web-browser is sending requests as below
enter image description here

Please suggest me what am I missing?
Also If I need to add some additional information please let me know.

Answer

Finally I got it working by creating a new type 'postList' and defined it as below

var { nodeInterface, nodeField } = nodeDefinitions(
  (globalId) => {
    var { type, id } = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    }else if (type==='postList') {
      return getpostList(id);
    } else{
      return null;
    }

  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    }else if (obj instanceof postList) {
      return postListType;
    }else{
      return null;
    }
  }
);

In database.js

class postList {}

postList.id = "Post_id";

export {postList}
export function getpostList(id) {
  return new postList
}

and under root fields as below

var postListType = new GraphQLObjectType({
  name: 'postList',
  description: 'List of posts',
  fields: () => ({
    id: globalIdField('postList'),
    posts: {
      type: postConnection,
      description: 'List of posts',
      args: {
       ...connectionArgs,
        query: {type: GraphQLString}
      },
      resolve: (_, args) => connectionFromPromisedArray(getAllPosts(_,args), args),
    },
  }),
  interfaces: [nodeInterface],
});

var Root = new GraphQLObjectType({
  name: 'Root',
  fields: () => ({
    node: nodeField,
    postList: {
      type: postListType,
      resolve:(rootValue)=> {
        return getpostList()
      }
    },
  })
});
Comments