美文网首页
GraphQL 的 Queries 和 Mutations

GraphQL 的 Queries 和 Mutations

作者: 弱冠而不立 | 来源:发表于2021-07-08 13:39 被阅读0次

    官方文档链接:Queries and Mutations
    本文概述的都是最基础的查询语句,具体的建立连接和发送请求的方式可以查看 Apollo 相关文档


    Fields (字段)

    在最简单的情况下,GraphQL 可以查询对象上的指定字段,看下下面这个简单的查询案例

    query {
      hero {
        name
      }
    }
    
    ### REULT ###
    
    {
      "data": {
        "hero": {
          "name": "R2-D2"
        }
      }
    }
    

    你可以很清楚地看见,返回的结果和查询的结构是一致的。
    在上面的案例中,就简单获取了 hero 的 name,但是某个查询的字段也可能是对象。下面这个例子就是字段嵌套子对象的情况。

    query {
      hero {
        name
        # Queries can have comments!
        friends {
          name
        }
      }
    }
    
    ### RESULT ###
    
    {
      "data": {
        "hero": {
          "name": "R2-D2",
          "friends": [
            {
              "name": "Luke Skywalker"
            },
            {
              "name": "Han Solo"
            },
            {
              "name": "Leia Organa"
            }
        ]
    }
    

    GraphQL 的查询语句会遍历字段中所有相近的对象,尽量让客户端在一个请求中获取大量的相关数据,而不是多次请求。

    Arguments (参数)

    在实际的请求过程中,我们都需要请求符合某个条件的指定数据,所以在 GraphQL 中我们也可以将参数传递给字段,就像下面这样:

    query {
      human(id: "1000") {
        name
        height
      }
    }
    
    ### RESULT ###
    
    {
      "data": {
        "human": {
          "name": "Luke Skywalker",
          "height": 1.72
        }
      }
    }
    

    Operation Name (操作名称)

    上面的例子都是直接使用 query 这个关键字作为查询名称的(官方文档省略了前面的query)但是实际的开发过程中,肯定不希望代码描述太过模糊,所以可以给操作设定名称

    query HeroNameAndFriends {
      hero {
        name
        friends {
          name
        }
      }
    }
    

    不光是 query 操作,后续的 mutation 和 subscription 都可以指定操作名称用于区分不同的条件语句。

    Variables (变量)

    光能够指定明确的参数值肯定是不符合开发要求的,很多时候我们一个 query 语句肯定要给不同的参数值去查询的,这个时候就可以使用变量进行传参:

    query HeroNameAndFriends($episode: Episode) {
     hero(episode: $episode) {
       name
       friends {
         name
       }
     }
    }
    
    --- variables ---
    {
     "episode": "JEDI"
    }
    
    ### RESULT ### 
    
    {
     "data": {
       "hero": {
         "name": "R2-D2",
         "friends": [
           {
             "name": "Luke Skywalker"
           },
           {
             "name": "Han Solo"
           },
           {
             "name": "Leia Organa"
           }
         ]
       }
     }
    }
    

    简单概括一下上面的例子:

    1. 使用 $variableName 代替静态的查询值
    2. 将 $variableName 作为查询的形式参数
    3. 传递实参进入 $variableName

    另外和 JS 的函数传参一样,也可以给个默认的变量值

    query HeroNameAndFriends($episode: Episode = JEDI) {
      hero(episode: $episode) {
        name
        friends {
          name
        }
      }
    }
    

    Aliases (别名)

    上面所有例子的情况,都有一个默认的前提,那就是服务器端的字段和前端所需的字段都是吻合的。那如果要是前端所需的字段需要换个别名再去渲染那该怎么办呢?下面的例子就能满足这样的需求:

    {
      empireHero: hero(episode: EMPIRE) {
        name
      }
      jediHero: hero(episode: JEDI) {
        name
      }
    }
    
    ### RESULT ###
    
    {
      "data": {
        "empireHero": {
          "name": "Luke Skywalker"
        },
        "jediHero": {
          "name": "R2-D2"
        }
      }
    }
    

    上面的例子就是,两个 hero 字段被重新换名了然后再返回给客户端。

    Fragments (片段)

    继续上面使用别名的场景,如果客户端给同一数据类型定义了两个不同的别名,然后又恰好不幸的是,查询的数据结构又很复杂,但是我们又不想再写一遍完全一样的数据结构怎么办?下面这个例子就能解决这种问题:

    {
      leftComparison: hero(episode: EMPIRE) {
        ...comparisonFields
      }
      rightComparison: hero(episode: JEDI) {
        ...comparisonFields
      }
    }
    
    fragment comparisonFields on Character {
      name
      appearsIn
      friends {
        name
      }
    }
    
    ### RESULT ###
    
    {
      "data": {
        "leftComparison": {
          "name": "Luke Skywalker",
          "appearsIn": [
            "NEWHOPE",
            "EMPIRE",
            "JEDI"
          ],
          "friends": [
            {
              "name": "Han Solo"
            },
            {
              "name": "Leia Organa"
            },
            {
              "name": "C-3PO"
            },
            {
              "name": "R2-D2"
            }
          ]
        },
        "rightComparison": {
          "name": "R2-D2",
          "appearsIn": [
            "NEWHOPE",
            "EMPIRE",
            "JEDI"
          ],
          "friends": [
            {
              "name": "Luke Skywalker"
            },
            {
              "name": "Han Solo"
            },
            {
              "name": "Leia Organa"
            }
          ]
        }
      }
    }
    

    你可以看到上面就是客户端需要查询两派不同的 hero 但是它们的属性基本相同,这个时候我们肯定不希望重复地去写两次类型声明,这个时候我们就可以预设好一个 Fragments 去复用。另外如果你要在 Fragments 里使用变量也是可以的:

    query HeroComparison($first: Int = 3) {
     leftComparison: hero(episode: EMPIRE) {
       ...comparisonFields
     }
     rightComparison: hero(episode: JEDI) {
       ...comparisonFields
     }
    }
    
    fragment comparisonFields on Character {
     name
     friendsConnection(first: $first) {
       totalCount
       edges {
         node {
           name
         }
       }
     }
    }
    

    Directives (指令)

    上面的变量的例子,已经能帮助我们动态地获取想要的后端数据了,但有时候我们还可能需要根据变量来动态地去更改我们的结构。例如,有时候渲染某个 UI 组件需要指定的条件,不符合这个条件我们就不渲染这个 UI 组件。下面这个例子就展示了如何使用 directives 关键字去动态地更改我们需要查询的数据结构:

    query Hero($episode: Episode, $withFriends: Boolean!) {
      hero(episode: $episode) {
        name
        friends @include(if: $withFriends) {
          name
        }
      }
    }
    --- variables ---
    {
      "episode": "JEDI",
      "withFriends": false
    }
    
    ### RESULT ###
    
    {
      "data": {
        "hero": {
          "name": "R2-D2"
        }
      }
    }
    

    简单解释一下上面这个例子,当 withFriends 的值为 false 时,该 hero 结构就不需要对应的 friends 属性了。

    Mutations (变更)

    刚刚所有的讨论都是围绕着请求数据,但我们肯定也需要一种能够修改服务器端数据的方法。在 REST 风格的请求方式下,尽管 GET 也能修改服务端数据,但通常情况下我们还是使用 POST 去修改服务端数据。GraphQL 也是类似的逻辑,虽然 query 也可以实现数据的写入,但任何的写入操作都应该用 mutation 关键字。

    就像 query 一样,mutation 操作也可以返回指定的对象类型。它可以返回更新后的最新状态。样例如下:

    mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
      createReview(episode: $ep, review: $review) {
        stars
        commentary
      }
    }
    --- variables ---
    {
      "ep": "JEDI",
      "review": {
        "stars": 5,
        "commentary": "This is a great movie!"
      }
    }
    
    ### RESULT ###
    
    {
      "data": {
        "createReview": {
          "stars": 5,
          "commentary": "This is a great movie!"
        }
      }
    }
    

    这样我们在更新一个字段的时候,我们就可以在一次请求中更新并获取最新的值。
    另外需要注意的是:Query 操作是并行的,而 Mutation 操作是串行的,这就意味着如果你在一次 request 中发送两次 CreateReviewForEpisode ,那么第一次一定会在第二次开始之前结束,用以确保不阻塞自己。
    另外,如果你不能确定从服务端返回的是哪种类型的话,你还可以加上 __typename 这个字段 (两条下划线)。

    相关文章

      网友评论

          本文标题:GraphQL 的 Queries 和 Mutations

          本文链接:https://www.haomeiwen.com/subject/zfwpultx.html