如何在解析字段之前对GraphQL项目进行充气?

时间:2018-02-13 15:44:25

标签: node.js graphql graphql-js

我在节点中关注GraphQL的this教程。我已经完成了教程,但我现在正在扩展。

它是基于XML的goodreads API之上的GraphQL API。我很难与作者打交道,书中有作者有书等问题。

考虑以下两个GraphQLObjects:

const BookType = new GraphQLObjectType({
    name: 'Book',
    description: '...',

    fields: () => ({
        title: {
            type: GraphQLString,
            resolve: xml =>
                xml.title[0]
        },
        isbn: {
           type: GraphQLString,
            resolve: xml =>
                xml.isbn[0]
        },
        authors: {
            type: GraphQLList(AuthorType2),
            resolve: xml =>
                xml.authors[0].author
        }
    })
});

const AuthorType = new GraphQLObjectType({
    name: 'Author',
    description: '...',

    fields: () => ({
        name: {
            type: GraphQLString,
            resolve: xml =>
                xml.name[0]
        },

        books: {
            type: GraphQLList(BookType),
            // if author not inflated, this fails
            resolve: xml => xml.books[0].book
        }

        //here could be another item that fails on uninflated authors
    })
});

根API在/ author上提供了一个完全扩展的作者,以及书籍,而书籍又有一段作者数据(假设它只有id和名称)。

我的问题是如何将这位简化的作者扩展到完整的状态,包括书籍并解决这些问题。我在书中解析作者字段时无法做到这一点,因为用户可能只需要作者的名字,因此加载了不需要的数据。

在解析书籍时我也做不到,从那时起如果又增加了另一个需要膨胀状态的领域,就没有办法保存状态,所以每个作者必须发生两次通货膨胀。

有人可以解释一下吗?有没有办法在解析它的字段时改变AuthorType的状态?其他一些解决方法?谢谢!

2 个答案:

答案 0 :(得分:0)

可能的解决方案是查看实际查询的字段。 resolve函数的第四个参数是较小的使用位,称为info。在其中,您可以浏览针对特定字段查询的fieldNode树。

您可以在authors字段解析功能中使用该信息来决定您是否要加载额外数据。类似的东西:

authors: {
    type: GraphQLList(AuthorType),
    resolve: (xml, args, context, info) => {
        if (!info.fieldNodes[0].selectionSet.selections....) // It's a pretty robust structure 
            return xml.authors[0].author;

        return loadAuthors(xml.title[0]) // However you load authors...
    }
}

关于字段的类型。您可以查看GraphQL interface and union types

答案 1 :(得分:0)

所以我一直在环顾四周,事实证明这不是解决这个问题的正确方法。最好使用某种类似于dataloader的每请求链接,并让每个需要额外端点的字段调用dataloader。这样,如果没有查询需要详细信息请求的字段,则不会进行第二次调用。此外,由于缓存,如果查询的多个字段需要详细调用,则只调用一次并缓存。

    books: {
        type: GraphQLList(BookType),
        // if author not inflated, this fails
        resolve: (obj, args, context) => {
            return context.booksLoader.load(obj.id)
                   .then(obj => obj.books)
        }
    }

    someOther: {
        type: GraphQLList(BookType),
        // if author not inflated, this fails
        resolve: (obj, args, context) => {
            return context.booksLoader.load(obj.id)
                   .then(obj => obj.someOther)
        }
    }