了解 GraphQL 中的查询

介绍

在本教程中,我们将深入研究 GraphQL 中的查询,以便您更好地了解如何从 GraphQL 服务器中获取数据. 我们将涵盖字段,参数,代名词,操作语法等。

田野

GraphQL 是基于对对象提出特定 fields 请求的,因此,我们不能成功地谈论查询而不谈论字段,查询是客户端使用的构造来从服务器请求特定字段。

鉴于 GraphQL 结构以便在所有请求中对一个端点进行最佳曝光,请求结构以要求特定的字段,服务器结构相同,以便响应所请求的确切字段。

考虑一个客户端希望从 API 终端请求足球玩家的情况,请求将如下结构:

1{
2    players {
3        name
4    }
5}

这是一个典型的 GraphQL 查询. 查询由两个不同的部分组成:

  • 根域(玩家):包含使用负载的对象
  • 使用负载(名称):客户端要求的域(s)

这是 GraphQL 不可或缺的一部分,因为服务器知道客户端正在询问哪些字段,并且总是用这些准确的数据回应。

1{
2    "players": [
3        {"name": "Pogba"},
4        {"name": "Lukaku"},
5        {"name": "Rashford"},
6        {"name": "Marshal"}
7    ]
8}

该字段名称返回一个字符串类型,在这种情况下,曼联球员的名字。然而,我们不仅限于字符串:我们可以拥有所有数据类型的字段,就像根字段玩家返回了一系列的项目一样。

例如,在我们的最后一个查询中,我们可以重新定义查询,从列表中选择一个单独的玩家,并查询有关该玩家的更多数据。

论点

GraphQL 查询允许我们将参数传输到查询字段和嵌入式查询对象中。您可以将参数传输到查询中的每个字段和每个嵌入式对象中,以进一步深化您的查询并进行多个检索。

回到我们以前的情况,比如衬衫大小鞋子大小等特定玩家套件的细节,首先,我们需要通过输入一个参数id来确定玩家从玩家列表中,然后在查询效能负载中定义我们想要的字段:

1{
2    player(id : "Pogba") {
3        name,
4        kit {
5            shirtSize,
6            bootSize
7        }
8    }
9}

在这里,我们正在请求播放器Pogba上的所需字段,因为我们将id参数传入查询中。 与字段一样,没有类型限制。 参数也可能有不同的类型。 与id参数的上一个查询的结果将如下:

 1{
 2    "player": {
 3        "name": "Pogba",
 4        "kit": [
 5            {
 6                "shirtSize": "large",
 7                "shoeSize": "medium"
 8            }
 9        ]
10    }
11}

这里的一个可能的陷阱是,GraphQL查询对于单个项目和项目列表看起来几乎相同. 在这些情况下,请记住,我们总是知道根据图表中定义的预期是什么。

此外,GraphQL查询是交互式的,因此您可以随意将更多字段添加到根字段对象中,因此,作为客户端,您可以灵活地避免循环旅行,并在单个请求中要求尽可能多的数据。

现在,如果我们想为两个玩家取出相同的字段,而不仅仅是一个呢?这就是 aliases 进入的地方。

阿利亚斯

如果您仔细看看我们最后一个例子,您会注意到结果对象字段:

 1// result....
 2"player": {
 3    "name": "Pogba",
 4    "kit": [
 5        {
 6            "shirtSize": "large",
 7            "shoeSize": "medium"
 8        }
 9    ]
10}

匹配查询字段:

1// query.... has matching fields with the result
2player(id : "Pogba") {
3    name,
4    kit {
5        shirtSize,
6        bootSize
7    }
8}

但是没有论点:

1(id : "Pogba")

因此,我们不能用不同的论点直接查询相同的玩家字段,也就是说,我们不能做这样的事情:

 1{
 2    player(id : "Pogba") {
 3        name,
 4        kit {
 5            shirtSize,
 6            bootSize
 7        }
 8    }
 9    player(id : "Lukaku") {
10        name,
11        kit {
12            shirtSize,
13            bootSize
14        }
15    }
16}

我们不能做到这一点,但我们可以做的是使用代名,它们允许我们将一个字段的结果重命名为我们想要的任何东西。

 1{
 2    player1: player(id: "Pogba") {
 3        name,
 4        kit {
 5            shirtSize,
 6            shoeSize
 7        }
 8    }
 9    player2: player(id: "Lukaku") {
10        name,
11        kit {
12            shirtSize,
13            shoeSize
14        }
15    }
16}

在这里,这两个玩家字段会发生冲突,但由于我们可以将它们命名为不同的名称player1player2,我们可以在一个请求中获得两个结果:

 1{
 2    "data": {
 3        "player1": {
 4            "name": "Pogba",
 5            "kit": [
 6                {
 7                    "shirtSize": "large",
 8                    "shoeSize": "medium"
 9                }
10            ]
11        },
12        "player2": {
13            "name": "Lukaku",
14            "kit": [
15                {
16                    "shirtSize": "extralarge",
17                    "shoeSize": "large"
18                }
19            ]
20        }
21    }
22}

现在使用代名词,我们已经成功查询了相同的字段与不同的论点,并获得了预期的答案。

运作 Syntax

到目前为止,我们一直在使用短语操作语法,我们没有明确要求定义操作名称或类型。在生产中,使用操作名称和类型是最好的做法,以帮助您的代码库变得不那么模糊。

操作语法包括两个核心:

  • 可能是查询、突变或订阅的操作类型 用于描述您打算执行的操作类型.
  • 可能是任何有助于您与您试图执行的操作相关的操作名称

现在,我们可以重写我们以前的示例,并添加一个操作类型和名称,如下:

1query PlayerDetails{
2    player(id : "Pogba") {
3        name,
4        kit {
5            shirtSize,
6            bootSize
7        }
8    }
9}

在本示例中,查询是操作类型,PlayerDetails是操作名称。

变量

到目前为止,我们一直在直接将所有参数传入查询字符串中。在大多数情况下,我们传递的参数都是动态的。例如,假设客户端想要的细节来自文本输入表格或下载菜单。我们传入查询字符串的参数必须是动态的,而为了做到这一点,我们需要使用 _variables。

考虑到我们最后一个例子,如果我们想使播放器动态,以便返回选定的播放器的详细信息,我们将不得不将播放器的ID值存储在变量中,并将其传输到操作名称和查询参数中,如下:

1query PlayerDetails ($id: String){
2    player (id : $id) {
3        name,
4        kit {
5            shirtSize,
6            bootSize
7        }
8    }
9}

在这里,‘$title: String’是变量定义,而‘title’是变量名称,前缀为‘$’,然后是类型,在这种情况下是 String,这意味着我们可以避免手动插入字符串来构建动态查询。

碎片

看看我们的查询,你会注意到玩家字段几乎是相同的,对于两个玩家:

1name,
2        kit {
3            shirtSize,
4            bootSize
5        }

为了更高效地处理我们的查询,我们可以将这个共享逻辑提取到玩家领域的可重复使用的片段中,如下:

 1{
 2    player1: player(id: "Pogba") {
 3        ...playerKit
 4    }
 5    player2: player(id: "Lukaku") {
 6        ...playerKit
 7    }
 8}
 9
10fragment playerKit on player {
11    name,
12    kit {
13        shirtSize,
14        shoeSize
15    }
16}

提取一块共享代码并在多个领域中重复使用的能力是一个关键概念,可以帮助开发人员避免在开发中甚至在生产中重复自己。

指令

GraphQL 指令为我们提供了告诉服务器在响应我们的查询时是否要包括跳过特定字段的方法,在 GraphQL 中有两个内置指令可以帮助我们实现这一目标:

  • @skip:当输入的值是真的时跳过特定字段
  • @include:当输入的值是真的时包含特定字段

让我们添加一个Boolean指令,然后在服务器上跳过@skip指令:

1query PlayerDetails ($playerShirtDirective: Boolean!){
2    player(id: "Pogba") {
3        name,
4        kit {
5            shirtSize @skip(if: $playerShirtDirective)
6            bootSize
7        }
8    }
9}

接下来我们要做的就是在我们的查询变量中创建playerShirtDirective指令,并将其设置为真:

1// Query Variables
2{
3  "itemIdDirective": true
4}

这将现在返回无衬衫尺寸的可用性:

1"player": {
2    "name": "Pogba",
3    "kit": [
4        {
5            "shoeSize": "medium"
6        }
7    ]
8}

我们可以使用@include指令来扭转这种情况,它与@skip指令相反,您可以使用它来通过在查询中代替@skip指令以@include来扭转服务器上的这种跳过操作。

结论

在本文中,我们讨论了 GraphQL 查询的细节。

如果您想了解更多关于 GraphQL 的信息,请参阅 GraphQL 官方文件. 如果您想尝试使用 GraphQL 创建项目,请尝试我们的 如何在 Ubuntu 18.04 上使用 Node.js 和 MongoDB 构建和部署 GraphQL 服务器教程。

Published At
Categories with 技术
Tagged with
comments powered by Disqus