如何在解析字段之前膨胀 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 和 ApolloStack 解析联合/接口字段
如何知道 Sangria GraphQL 中对象解析器中的请求字段