如何使用不同的字段生成相同的 graphql 查询

Posted

技术标签:

【中文标题】如何使用不同的字段生成相同的 graphql 查询【英文标题】:How to generate the same graphql query with different fields 【发布时间】:2019-07-05 06:57:39 【问题描述】:

我正在使用graphql-tag,所以我将使用该语法。

假设我有这个查询:

const query = gql`
 query user(id: String) 
  user(id: $id) 
   id
  
 
`

如果在不同的调用中,除了id 之外,我还想要字段usernameemail,而无需再次重写整个查询,那么重用同一个查询文档节点的最佳模式是什么:

const query = gql`
 query user(id: String) 
  user(id: $id) 
   id
   username
   email
  
 
`

我在前端使用react-apollo,如果这让事情变得更有趣的话。

编辑:

只是为了澄清......这样的事情

const userIdFrag = gql`
  fragment UserId on User 
    id
  
`

const fullUserFrag = gql`
  fragment FullUser on User 
    id
    username
    email
  
`

const generateQuery = (documentNode) => 
  return gql`
   query user(id: String) 
      user(id: $id) 
       ...documentNode
      
     
     $documentNode
  `


const idQuery = generateQuery(userIdFrag);
const fullUserQuery = generateQuery(fullUserFrag);

(上述方法确实有效,但控制台中的 graphql 出现错误,这让我相信这不是我应该做的事情)

【问题讨论】:

您可以查看片段 - apollographql.com/docs/react/advanced/fragments.html,尽管您仍然需要定义查询 2 次​​span> 是的,我知道片段,我想知道是否有更好的方法可以避免每次都写查询签名 您遇到的错误是什么? @ric0 错误基本上说“在 graphql 查询中未使用 documentNode”,即使 $documentNode 片段正在添加到其中 【参考方案1】:

根据您的评论,以下应该有效:


const generateQuery = (documentNode, fragment) => 
  return gql`
   query user(id: String) 
      user(id: $id) 
       ...$fragment
      
     
     $documentNode
  `


const idQuery = generateQuery(userIdFrag, 'UserId');
const fullUserQuery = generateQuery(fullUserFrag, 'FullUser');

基本上使用的片段名称是实际需要传播的片段名称,而整个 documentNode 对象放在最后,在查询的右括号之后

【讨论】:

这很有效,现在我看到它写出来了,这更有意义。我可能会做出的一项更改是,您实际上可以从位于...的 documentNode 获取片段的名称。node.definitions[0].name.value 是的,当然。我没想到,你的方式更有效。【参考方案2】:

我不是该主题的专家,但这是我能够找到的。 (如果您发现我的假设有任何错误,请告诉我)。

我发现this article 对动态生成gql 查询/突变有一些好处。使用静态方法似乎可以获得一些不错的好处,尽管它需要更多的输入。

但是,如果您确实需要动态字段,我找不到任何关于使用 GraphQL 提供的 @skip 指令的坏处。 Here the docs ref.

对于在react-apollothey also have it in their docs中使用的情况。

因此,您的代码最终可能看起来像这样:

const query = gql`
 query user($id: String, $skipUserMeta: Boolean!) 
  user(id: $id) 
   id
   username @skip(if: $skipUserMeta)
   email @skip(if: $skipUserMeta)
  
 
`

您只需将skipUserMeta 作为变量传递到id 字段旁边。

注意:我实际上找到了一个关于the exact same approach here的视频

【讨论】:

以上是关于如何使用不同的字段生成相同的 graphql 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在两个字段 prisma-graphql 中使用相同的生成 ID

多个字段解析器使用不同的查询参数解析相同的 REST API

如何使用相同的参数查询 Graphql 2 对象

GraphQL - 在联合内的不同类型中使用相同的字段名称

Apollo / GraphQL 具有不同参数的相同查询

使用具有不同片段字段的相同中继根查询的多个 react-router-relay 路由