抽象类型Node必须在运行时为字段Root.node解析为Object类型,其值为“\”,收到\“null \”。“

时间:2016-08-26 12:24:54

标签: node.js reactjs relayjs

我正在使用react和relay实现搜索功能。 下面是我的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;
       });
      }
    },
  })
});

以下是我的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)
        }
      });
  })
}

现在我想通过$ query变量获取所有帖子 所以在视图中我这样写了

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
              }
            }
          }
        }
      }
    `,
  },
});

在我有路线

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,
  }]
}]

事情正在/ graphql上工作 Graphql UI

但是当我从网站搜索时,它会在响应中生成错误

{
  "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
        }
      ]
    }
  ]
}

因为我的网络浏览器正在发送请求,如下所示 enter image description here

请告诉我我错过了什么? 另外如果我需要添加一些其他信息,请告诉我。

4 个答案:

答案 0 :(得分:2)

问题可能出在您的nodeDefinitions()功能中。第一个回调(也称为idFetcher)必须返回单个对象。但是,我在您的定义中看到您返回一个集合

var { nodeInterface, nodeField } = nodeDefinitions(
  (globalId) => {
    var { type, id } = fromGlobalId(globalId);
    ...
    }else if (type === 'Post') {
      return getPosts(); // this should be getPost(id)
    }
);

这就是为什么你的下一个回调,即typeResolver失败并返回null。

var { nodeInterface, nodeField } = nodeDefinitions(
  ...
  (obj) => {
    ...
    // here you get Promise/Collection instead of single Post instance, therefore condition failed
    }else if (obj instanceof Post) {
      return postType;
    }
    return null;
  }
);

答案 1 :(得分:0)

LordDave的回答揭示了代码中的一个问题。正如您在回答中所评论的那样,all_posts的{​​{1}}字段无效。

如果您在数据库代码中使用了mongoose库,我发现您的查询存在问题:

settingType

根据exec的文档,将您的查询更改为

Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec({}, function(err, posts) {
  if (err) {
    resolve({})
  } else {
    resolve(posts)
  }
});

return Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec(function(err, posts) { if (err) { resolve({}) } else { resolve(posts) } }); 返回承诺时,您甚至可以

exec

答案 2 :(得分:0)

最后,我通过创建一个新类型'postList'并将其定义如下

来实现它
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;
    }
  }
);

在database.js

class postList {}

postList.id = "Post_id";

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

并在根域下面

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()
      }
    },
  })
});

答案 3 :(得分:0)

当我使用InterfaceType并在InterfaceType <的if-elseif-else中的专门ObjectType之前检查TypeResolver时,我遇到了此问题/ p>