循环模式给出错误为“错误:模式必须包含唯一的命名类型,但包含多个名为”节点”的类型。”

时间:2018-10-22 14:06:12

标签: node.js graphql graphql-relay

我是使用nodejs的“ GraphQL”的新手。我陷入了双向模式映射。帖子<->作者。使用graphqlgraphql-relay模块。

以下是我们正在使用的两个模式。

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/rounded_corners_background"
android:weightSum="100">

<TableRow
    android:layout_height="0dp"
    android:layout_width="match_parent"
    android:layout_weight="40">

    <me.grantland.widget.AutofitTextView
        android:id="@+id/tvQuestion"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:textSize="40sp"
        android:layout_gravity="center"
        android:maxLines="1"
        app:minTextSize="12sp"
        android:paddingBottom="18dp"
        android:text="" />

</TableRow>

<TableRow
    android:layout_weight="15">

    <TextView
        android:id="@+id/textViewStableA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:layout_gravity="start"
        android:paddingStart="8dp"
        android:text="" />

    <TextView
        android:id="@+id/tvAnswerA"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="100"
        android:layout_gravity="start"
        android:gravity="center"
        android:text="" />
</TableRow>

<TableRow
    android:layout_weight="15">

    <TextView
        android:id="@+id/textViewStableB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="" />

    <TextView
        android:id="@+id/tvAnswerB"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="100"
        android:gravity="center"
        android:text="" />
</TableRow>

<TableRow
    android:layout_weight="15">

    <TextView
        android:id="@+id/textViewStableC"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="" />

    <TextView
        android:id="@+id/tvAnswerC"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="100"
        android:gravity="center"
        android:text="" />
</TableRow>

<TableRow
    android:layout_weight="15">

    <TextView
        android:id="@+id/textViewStableD"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="" />

    <TextView
        android:id="@+id/tvAnswerD"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="100"
        android:gravity="center"
        android:text="" />
</TableRow>

一旦合并了GraphQL的上述架构,我就会遇到以下错误。

--posts.js // here we are requiring authors.js 
const {
    AuthorType,
    schema: AuthorSchema,
    AuthorsConnection
} = require('./authors');

class Post {}

const {
    nodeInterface,
    nodeField
} = nodeDefinitions(
    globalId => {
        const {
            type,
            id
        } = fromGlobalId(globalId);
        // return based on the id
        return DataSource['posts'][0];
    },
    obj => {
        console.log(" : PostType : ", PostType);
        // type to be return 
        return Post;
    }
);

const PostType = new GraphQLObjectType({
    "name": "PostType",
    "description": "Posts type and it's relevant fields",
    "fields": () => ({
        "id": globalIdField('Post'),
        "title": {
            "type": GraphQLString
        },
        "body": {
            "type": GraphQLString
        },
        "author": {
            "type": AuthorsConnection,
            "resolve": (parent, argument, root, currentSdl) => {
                console.log("v1, v2, v3, v4  :", parent);
                if (parent.author)
                    return connectionFromArray(DataSource['authors'], {})
                return [];
            }
        }
    }),
    isTypeOf: Post,
    interfaces: [nodeInterface]
});

const {
    connectionType: PostsConnection,
    edgeType: GQLPostEdge
} = connectionDefinitions({
    name: "Post",
    nodeType: PostType
});
module.exports = exports = {
    PostType,
    PostsConnection,
    schema: {
        post: nodeField,
        posts: {
            type: PostsConnection,
            resolve: (root, v2, v3) => {
                return connectionFromArray(DataSource['posts'], {});
            }
        }
    }
};

--authors.js // here we have required posts.js

const {
    PostType,
    PostsConnection
} = require('./posts');

class Author {}

const {
    nodeInterface,
    nodeField
} = nodeDefinitions(
    globalId => {
        const {
            type,
            id
        } = fromGlobalId(globalId);
        // return based on the id
        return DataSource['authors'][0];
    },
    obj => {
        console.log(" : Authorype : ", Authorype);
        // type to be return 
        return Author;
    }
);

const AuthorType = new GraphQLObjectType({
    "name": "AuthorType",
    "description": "Author type and it's relevant fields",
    "fields": () => ({
        "id": globalIdField('Author'),
        "firstName": {
            "type": GraphQLString
        },
        "lastName": {
            "type": GraphQLString
        },
        authorPosts: {
            type: PostsConnection,
            resolve: (parent, args, root, context) => {
                return connectionFromArray(DataSource['posts'], {});
            }
        }
    }),
    isTypeOf: null,
    interfaces: [nodeInterface]
});

const {
    connectionType: AuthorsConnection,
    edgeType: GQLAuthorEdge
} = connectionDefinitions({
    name: "Author",
    nodeType: AuthorType
});

module.exports = exports = {
    AuthorType,
    AuthorsConnection,
    schema: {
        author: nodeField,
        authors: {
            type: AuthorsConnection,
            resolve: (root, v2, v3) => {
                return connectionFromArray(DataSource['authors'], {});
            }
        }
    }
};

我尝试调试此问题,以下是我观察到的以下情况。

  • 一旦我将“作者”字段从帖子架构更改为 “ AuthorsConnection”开始工作。
  • 或者如果删除了“作者”字段 从帖子架构开始工作。

请让我知道这里的问题,它与Error: Schema must contain unique named types but contains multiple types named "Node". 函数有关吗?

2 个答案:

答案 0 :(得分:1)

它确实与nodeDefinitions函数有关。来自graphql-relay文档:

  

nodeDefinitions返回对象可以实现的Node接口,并返回要包含在查询类型中的node根字段。为此,它需要一个函数来解析对象的ID,并确定给定对象的类型。

您要调用两次,这导致Node类型被定义两次,并且您要引用其中一种:

schema: {
    post: nodeField,

// ...

schema: {
    author: nodeField,

这引起了错误-Node的两个独立实例无效。

解决方案是只调用nodeDefinitions一次,然后将对生成的nodeFieldnodeInterface的引用传递到相关位置。然后,您的globalId => {...}函数将需要查看type来弄清楚如何获得相关记录,无论是作者还是帖子。

答案 1 :(得分:0)

上面的答案由@Benjie给出。我找到了解决导致Error: Schema must contain unique named types but contains multiple types named "Node".错误的问题的方法。

以下是我们以模块化方式制作graphql时要检查的关键点。

  • 不要创建新的类型实例,例如:const PostType = new GraphQLObjectType({})应该始终发送单个对象,而不是每次都发送新对象。
  • 仅使用nodeDefinations一次。
  • 检查将出现的常见javascript问题中的周期性问题。

谢谢。