【问题标题】:How should I query and match data from the same response in GraphQL with Apollo Client and Link Rest?我应该如何使用 Apollo Client 和 Link Rest 从 GraphQL 中的同一响应中查询和匹配数据?
【发布时间】: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,我们必须处理它:)

标签: graphql apollo-client apollo-link-rest


【解决方案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 有点不稳定,所以没有承诺。

【讨论】:

    猜你喜欢
    • 2020-01-18
    • 2018-07-17
    • 2019-03-13
    • 2020-10-23
    • 2018-02-10
    • 2019-09-11
    • 2019-12-21
    • 2022-12-02
    • 2018-11-06
    相关资源
    最近更新 更多