如何在解析字段之前膨胀 GraphQL 项目?

Posted

技术标签:

【中文标题】如何在解析字段之前膨胀 GraphQL 项目?【英文标题】:How to inflate GraphQL items before resolving fields? 【发布时间】:2018-07-24 00:59:54 【问题描述】:

我正在关注this node.js 中的 GraphQL 教程。我已经完成了教程,但现在我自己扩展了。

它是基于 XML 的 goodreads API 之上的 GraphQL API。我无法处理作者有书有作者有书等问题。

考虑以下两个 GraphQLObject:

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 上,并提供一个完全扩展的作者,以及依次具有作者数据的 sn-p 的书籍(假设它只有 id 和名称)。

我的问题是如何将这个缩​​减的作者扩展为完整状态,包括书籍并解决这些问题。在解析书中的作者字段时我不能这样做,因为用户可能只需要作者的姓名,因此加载了不需要的数据。

解析书籍时我也不能这样做,因为如果添加了另一个也需要膨胀状态的字段,则无法保存状态,因此每个作者必须发生两次膨胀。

谁能解释一下?有没有办法在解析它的字段期间改变 AuthorType 的状态?其他一些解决方法?谢谢!

【问题讨论】:

【参考方案1】:

一种可能的解决方案是查看实际查询了哪些字段。解析函数的第四个参数是一个较少使用的位,称为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。

【讨论】:

当然,您知道该请求什么。但是问题仍然存在:如果我们在 book 类型中有两个字段需要调用 book api,我仍然需要一种方法来获取一次,然后再检索(对于第二个字段)。此信息实际上并未为此提供方法。我认为某种状态字段是最好的 对不起,我刚刚发现这是在解析列表时,所以这是有道理的,谢谢 我找到了一个更好的解决方案并在下面发布,但您的解决方案在技术上是正确的。所以我不知道?【参考方案2】:

所以我一直在环顾四周,结果发现这不是解决此类问题的正确方法。最好使用某种针对每个请求的 chaching,例如 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)
        
    

【讨论】:

以上是关于如何在解析字段之前膨胀 GraphQL 项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Apollo GraphQL Server 中添加字段解析器

如何解决 graphql 查询中的嵌套项

如何使用 GraphQL 和 ApolloStack 解析联合/接口字段

如何知道 Sangria GraphQL 中对象解析器中的请求字段

如何使用 type-graphql 解析器函数获取 graphql 后端中的选定字段?

如何使用带有 ktor 框架的 graphql-kotlin 进行字段级解析器