我应该如何使用 Apollo Client 和 Link Rest 从 GraphQL 中的同一响应中查询和匹配数据?

Posted

技术标签:

【中文标题】我应该如何使用 Apollo Client 和 Link Rest 从 GraphQL 中的同一响应中查询和匹配数据?【英文标题】:How should I query and match data from the same response in GraphQL with Apollo Client and Link Rest? 【发布时间】:2019-12-01 13:00:45 【问题描述】:

我有以下疑问:

const getPage = gql`
    query Page($path: String!) 
        page(path: $path) @rest(type: "Page", path: "args.path") 
            blocks @type(name: Block) 
                name
                posts @type(name: Post) 
                    body
                    author
                
            
            authors @type(name: Author) 
                name
            
        
    

blocks.posts.author 中只有一个AuthorId。 authors 对象包含所有可用的作者。

我想用它的对应对象替换/匹配AuthorId。是否可以在一个查询中执行此操作?

我也不介意仅对 Author 进行单独查询(将缓存提取,不会发出新请求),但我仍然不知道如何通过 2 个查询匹配它。

示例 API 响应


   blocks: [
      
         posts: [
             
                id: 1,
                title: 'My post',
                author: 12,
             
         ]
      
   ],
   authors: [
      
         id: 12,
         name: 'John Doe'
      
   ]

我想要通过 1 个查询使 post 中的 author 成为完整的作者对象。

【问题讨论】:

根据指令,您似乎正在使用apollo-clientapollo-link-rest,但这在您的问题中未提及,也未在标签中反映出来。 谢谢,已添加。 我添加了一个应该可行的答案,尽管自从我使用该链接以来已经有一段时间了。如果您要包装一个非常基本的 REST 端点,这是一个简洁的库,但您应该考虑设置一个单独的 GraphQL 服务器作为网关,而不是用于更复杂的情况。这使您在如何解析字段方面具有更大的灵活性,并为缓存 REST 响应和其他功能开辟了道路,这些功能是 apollo-link-rest 无法实现的。 缓存将在浏览器级别使用 SW 解决,给我们更多的控制权。我们试图拥有您发布的此类解决方案,但您所拥有的需要一个单独的端点,因为我可以看到我们没有。我们无法改变这一点,它是一个像这样工作的 php API,我们必须处理它:) 【参考方案1】:

很好的问题。使用 GraphQL,您可以扩展任何字段并从中选择所需的确切子字段,因此,如果您也在后端使用 GraphQL,这将不是问题。您可以在此处执行一些解决方法:

如果所有作者对象都在您的 Apollo 缓存中,并且您可以访问每个作者的 id,则可以使用 ApolloClient.readFragment 访问其他属性,如下所示:

const authorId = ...; // the id of the author

const authorInfo = client.readFragment(
  id: authorId,
  fragment: gql`
    fragment AuthorInfo on Author 
      id
      name
      # anything else you want here
    
  `,
);

虽然值得注意的是,对于问题中的原始查询,如果您将所有 Author 对象作为查询的属性,您可以只使用 javascript 操作从 Author id 转到对象。

const authorId = ...; // the id of the author
data.page.authors.find(author => author.id === authorId);

【讨论】:

感谢您的详细回答,但这对我没有帮助。您的第一个建议假设我已经拥有我没有的 ID,一切都在同一个响应中。第二个是我们正在做并希望避免的事情,因为它会导致某些问题。 @wintercounter PostAuthor的类型定义是什么?根据您的问题,我假设 Post.author 是对作者的一些独特引用,无论是按名称还是 ID。您可以将 Apollo 缓存配置为使用任何字段(或字段组合)作为唯一标识符,因此第一种方法应该仍然有效。更多信息在这里:apollographql.com/docs/react/advanced/caching/#normalization 是的,您没看错,但authors 也将出现在相同的 API 响应中。所以回复基本是posts: [], authors: [],所以之前没有作者ID。 添加了示例 API 响应。【参考方案2】:

以下应该可以工作。

首先,使用@export 指令将作者ID 作为变量捕获。然后添加一个名称不是author 的新字段,并使用路径中的导出变量用@rest 装饰它。

所以查询看起来像这样:

query Page($path: String!) 
    page(path: $path) @rest(type: "Page", path: "args.path") 
        blocks @type(name: Block) 
            name
            posts @type(name: Post) 
                body
                author @export(as: "authorId")
                authorFull @rest(
                    path: '/authors/exportVariables.authorId'
                    type: 'Author'
                ) 
                    name
                
            
        
        authors @type(name: Author) 
            name
        
    

您可以使用fieldNameNormalizeroption 将响应中的author 属性重命名为具有不同名称的字段(例如authorId)。理想情况下,这仍然适用于上述内容,因此您可以避免使用像 authorFull 这样的奇怪字段名称,但 apollo-link-rest 有点不稳定,所以没有承诺。

【讨论】:

以上是关于我应该如何使用 Apollo Client 和 Link Rest 从 GraphQL 中的同一响应中查询和匹配数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 localStorage 与 apollo-client 和 reactjs 一起使用?

如何使用 Apollo Client 虚拟字段

如何使用 Apollo 工具为查询生成 Typescript 类型,包括 Apollo @client 和 @rest 指令?

使用 Redux Thunk 和 Apollo Graphql 做出反应 - 如何访问 client.query?

apollo-client 没有响应的标头

@apollo/client 、 apollo-client 和 apollo boost 之间的区别