graphql 嵌套查询_了解GraphQL中的查询

news/2024/7/5 21:20:08

graphql 嵌套查询

介绍 (Introduction)

In this tutorial, we’ll take an in-depth look at queries in GraphQL so that you better understand how to retrieve data from a GraphQL server. We will cover fields, arguments, aliases, operation syntax, and more. Once you have finished, you will be able to leverage the functionality of queries to build better API’s with GraphQL.

在本教程中,我们将深入研究GraphQL中的查询,以便您更好地了解如何从GraphQL服务器检索数据。 我们将介绍字段,参数,别名,操作语法等。 完成后,您将能够利用查询功能来通过GraphQL构建更好的API。

领域 (Fields)

GraphQL based on asking for specific fields on objects. We therefore can’t successfully talk about queries without talking about Fields. Queries are the construct used by the client to request specific fields from the server.

GraphQL基于请求对象上的特定字段。 因此,如果不谈论字段,就无法成功谈论查询。 查询是客户端用来从服务器请求特定字段的构造。

Given that GraphQL is structured to optimally expose one endpoint for all requests, queries are structured to request for specific fields, and the server is equally structured to respond with the exact fields being requested.

鉴于GraphQL的结构可以为所有请求最佳地公开一个端点,查询的结构可以请求特定的字段,服务器的结构也同样可以响应所请求的确切字段。

Consider a situation where a client wants to request for soccer players from an API endpoint. The query will be structured like this:

考虑一种情况,客户希望从API端点请求足球运动员。 查询的结构如下:

{
    players {
        name
    }
}

This is a typical GraphQL query. Taking a closer look, queries are made up of two distinct parts:

这是一个典型的GraphQL查询。 仔细研究一下,查询由两个不同的部分组成:

  • The root field (players) : The object containing the payload.

    root field (玩家):包含有效负载的对象。

  • The payload (name) : The field(s) requested by the client.

    payload (名称):客户端请求的字段。

This is an essential part of GraphQL because the server knows exactly what fields the client is asking for and always responds with that exact data. In the case of our example query, we could have this response:

这是GraphQL的重要组成部分,因为服务器确切地知道客户端要查询的字段,并始终以该确切的数据进行响应。 对于我们的示例查询,我们可以得到以下响应:

{
    "players": [
        {"name": "Pogba"},
        {"name": "Lukaku"},
        {"name": "Rashford"},
        {"name": "Marshal"}
    ]
}

The field name returns a String type, in this case, the names of the Manchester United players. However, we are not limited to just Strings: we can have fields of all data types, just like the root field players returns an array of items. Feel free to learn more about the GraphQL Type System in the GraphQL official docs.

字段name返回String类型,在这种情况下为曼联球员的名称。 但是,我们不仅限于字符串:我们可以拥有所有数据类型的字段,就像根字段players返回项数组一样。 随意在GraphQL官方文档中了解有关GraphQL类型系统的更多信息。

In production, we would want to do more than just returning names. For instance, in our last query, we can redefine the query to select an individual player from the list and query for more data on that player. To be able to do so, we’ll need a way to identify that player so we can get the details. In GraphQL, we can achieve this with Arguments.

在生产中,我们不仅要返回名称,还希望做更多的事情。 例如,在上一个查询中,我们可以重新定义查询以从列表中选择一个球员,并查询有关该球员的更多数据。 为此,我们需要一种识别该玩家的方法,以便我们获取详细信息。 在GraphQL中,我们可以使用Arguments.实现此目的Arguments.

争论 (Arguments)

GraphQL queries allow us to pass in arguments into query fields and nested query objects. You can pass arguments to every field and every nested object in your query to further deepen your request and make multiple fetches. Arguments serve the same purpose as your traditional query parameters or URL segments in a REST API. We can pass them into our query fields to further specify how the server should respond to our request.

GraphQL查询允许我们将参数传递到查询字段和嵌套查询对象中。 您可以将参数传递给查询中的每个字段和每个嵌套对象,以进一步加深您的请求并进行多次提取。 参数的用途与REST API中的传统query parametersURL segments相同。 我们可以将它们传递到查询字段中,以进一步指定服务器应如何响应我们的请求。

Back to our earlier situation of fetching a specific player’s kit details like shirt size or shoe size, first, we’ll have to specify that player by passing in an argument id to identify the player from the list of players, and then define the fields we want in the query payload:

回到我们之前获取特定球员装备详细信息(例如shirt sizeshoe size,首先,我们必须通过传递参数id来指定该球员,以从球员列表中识别球员,然后定义字段我们要在查询有效载荷中:

{
    player(id : "Pogba") {
        name,
        kit {
            shirtSize,
            bootSize
        }
    }
}

Here, we are requesting the desired fields on the player Pogba because of the id argument we passed into the query. Just like fields, there are no type restrictions. Arguments can be of different types, too. The result of the previous query with the id argument will look like the following:

在这里,由于传递给查询的id参数,我们需要在播放器Pogba上请求所需的字段。 就像字段一样,没有类型限制。 参数也可以是不同的类型。 具有id参数的上一个查询的结果将如下所示:

{
    "player": {
        "name": "Pogba",
        "kit": [
            {
            "shirtSize": "large",
            "shoeSize": "medium"             }
         ]

    }
}

One possible pitfall here is that GraphQL queries look almost the same for both single items and lists of items. In these situations, remember that we always know what to expect based on what is defined in the schema.

一个可能的陷阱是,对于单个项目和项目列表,GraphQL查询看起来几乎相同。 在这种情况下,请记住,我们总是知道基于架构中定义的内容。

Also, GraphQL queries are interactive, so you can add more fields to the root field object at will. That way, you, as the client, have the flexibility to avoid round trips and request for as much data as you want in a single request.

另外,GraphQL查询是交互式的,因此您可以随意向根字段对象添加更多字段。 这样,作为客户端,您可以灵活地避免往返,并在单个请求中请求所需的尽可能多的数据。

Now, what happens if we want to fetch the same fields for two players, not just one? That’s where aliases come in.

现在,如果我们想为两个玩家而不是一个获取相同的字段会发生什么? 这就是别名的来源。

别名 (Aliases)

If you take a closer look at our last example, you’ll notice that the result object fields:

如果仔细看一下我们的最后一个示例,您会注意到result对象字段:

// result....
"player": {
        "name": "Pogba",
        "kit": [
            {
            "shirtSize": "large",
            "shoeSize": "medium"             }
         ]

    }

match the query fields:

匹配查询字段:

//query.... has matching fields with the result
player(id : "Pogba") {
        name,
        kit {
            shirtSize,
            bootSize
        }
    }

but without the argument:

但没有参数:

(id : "Pogba")

Because of this, we can’t directly query for the same field player with different arguments. That is, we can’t do something like this:

因此,我们无法直接查询具有不同参数的同一个田野player 。 也就是说,我们不能做这样的事情:

{
    player(id : "Pogba") {
        name,
        kit {
            shirtSize,
            bootSize
        }
    } 
    player(id : "Lukaku") {
        name,
        kit {
            shirtSize,
            bootSize
        }
    }

}

We can’t do this, but what we can do is use aliases. They let us rename the result of a field to anything we want. For our example, to query for two players’ kit details, we’ll define our query like so:

我们无法做到这一点,但是我们可以做的就是使用别名。 他们让我们将字段的结果重命名为我们想要的任何内容。 对于我们的示例,要查询两个球员的装备详细信息,我们将定义查询,如下所示:

{
  player1: player(id: "Pogba") {
    name,
    kit {
        shirtSize,
        shoeSize
    }
  }
  player2: player(id: "Lukaku") {
    name,
    kit {
        shirtSize,
        shoeSize
    }
  }
}

Here, the two player fields would have conflicted, but since we can alias them to different names player1 and player2, we can get both results in one request:

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

{
  "data": {
    "player1": {
      "name": "Luke Skywalker",
        "kit": [
            {
            "shirtSize": "large",
            "shoeSize": "medium" 
            }
         ]
    },
    "player2": {
      "name": "Lukaku",
        "kit": [
            {
            "shirtSize": "extralarge",
            "shoeSize": "large" 
            } 
        ]
    }
  }
}

Now using aliases, we have successfully queried the same field with different arguments and gotten the expected response.

现在使用别名,我们已经成功地使用不同的参数查询了相同的字段,并获得了预期的响应。

操作语法 (Operation Syntax)

Until now, we have been using the shorthand operation syntax where we are not explicitly required to define either the operation name or type. In production, it is a best practice to use operation names and types to help make your codebase less ambiguous. It also helps with debugging your query in the case of an error.

到现在为止,我们一直在使用速记操作语法,在该语法中,我们没有明确要求定义操作名称或类型。 在生产中,最佳实践是使用操作名称和类型来帮助减少代码库的歧义。 如果出现错误,它也有助于调试查询。

The operation syntax comprises of two central things:

操作语法包含两个主要内容:

  • The operation type which could be either query, mutation, or subscription. It is used to describe the type of operation you intend to carry out.

    operation type可以是查询,变异或订阅。 它用于描述您打算执行的操作类型。

  • The operation name which could be anything that will help you relate with the operation you’re trying to perform.

    operation name可以是任何可以帮助您与要执行的操作相关的operation name

Now, we can rewrite our earlier example and add an operation type and name like this:

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

query PlayerDetails{
    player(id : "Pogba") {
        name,
        kit {
            shirtSize,
            bootSize
        }
    }
}

In this example, query is the operation type and PlayerDetails is the operation name.

在此示例中, query是操作类型,而PlayerDetails是操作名称。

变数 (Variables)

So far, we have been passing all our arguments directly into the query string. In most cases, the arguments we pass are dynamic. For example, let’s say the player the client wants details from comes from a text input form or a dropdown menu. The argument we pass into the query string has to be dynamic, and to do that, we need to use variables. Thus, variables are used to factor out dynamic values from queries and pass them as a separate dictionary.

到目前为止,我们一直在将所有参数直接传递到查询字符串中。 在大多数情况下,我们传递的参数是动态的。 例如,假设客户希望从中获取详细信息的播放器来自文本输入表单或下拉菜单。 我们传递给查询字符串的参数必须是动态的,为此,我们需要使用变量。 因此,变量用于从查询中排除动态值,并将它们作为单独的字典传递。

Considering our last example, if we wanted to make the player dynamic such that the selected player’s details are returned, we would have to store the player’s ID value in a variable and pass it into the operation name and query argument, like so:

考虑最后一个示例,如果我们想使播放器动态化,以便返回所选播放器的详细信息,则必须将播放器的ID值存储在变量中,并将其传递给操作名称和查询参数,如下所示:

query PlayerDetails ($id: String){
    player (id : $id) {
        name,
        kit {
            shirtSize,
            bootSize
        }
    }
}

Here, $title: String is the variable definition and title is the variable name. It is prefixed by $ followed by the type, which in this case is String. This means that we can avoid manually interpolating strings to construct dynamic queries.

在这里, $title: String是变量定义,而title是变量名。 它以$开头,后跟类型,在这种情况下为String。 这意味着我们可以避免手动插值字符串以构造动态查询。

碎片 (Fragments)

Looking at our query, you’ll notice that the player field is practically the same for both players:

查看我们的查询,您会注意到两个球员的player字段几乎相同:

name,
        kit {
            shirtSize,
            bootSize
        }

To be more efficient with our query, we can extract this piece of shared logic into a reusable fragment on the player field, like so:

为了提高查询效率,我们可以将这条共享逻辑提取到player字段上的可重用片段中,如下所示:

{
  player1: player(id: "Pogba") {     ...playerKit
  }
  player2: player(id: "Lukaku") {
    ...playerKit
  }
}

fragment playerKit on player {
    name,
    kit {
        shirtSize,
        shoeSize
    }
}

The ability to extract a piece of shared code and reuse it across multiple fields is a crucial concept that helps developers avoid repeating themselves in development and even in production. If you’re working on a deep layered codebase, you’ll find it rather useful and timely to reuse code rather than repeat your self across multiply components.

提取一段共享代码并在多个领域中重复使用的能力是至关重要的概念,它可以帮助开发人员避免在开发甚至生产中重复自己的工作。 如果您正在研究一个深层次的代码库,您会发现重用代码而不是在乘法组件之间重复自我非常有用且及时。

指令 (Directives)

GraphQL directives provide us with a way to tell the server whether to include or skip a particular field when responding to our query. There are two built-in directives in GraphQL that helps us achieve that:

GraphQL指令为我们提供了一种在响应我们的查询时告诉服务器是include还是skip特定字段的方法。 GraphQL中有两个内置指令可帮助我们实现这一目标:

  • @skip for skipping a particular field when the value passed into it is true.

    @skip用于在传递给它的值为true时跳过特定字段。

  • @include to include a particular field when the value passed into it is true.

    @include在传递给它的值为true时包括一个特定字段。

Let’s add a Boolean directive and skip it on the server with the @skip directive:

让我们添加一个Boolean指令,并使用@skip指令在服务器上跳过它:

query PlayerDetails ($playerShirtDirective: Boolean!){
    player(id: "Pogba") {
        name,
        kit {
            shirtSize @skip(if: $playerShirtDirective)
            bootSize
        }
    }
}

The next thing we’ll do is create the playerShirtDirective directive in our query variables and set it to true:

我们要做的下一件事是在查询变量中创建playerShirtDirective指令并将其设置为true:

// Query Variables
{
  "itemIdDirective": true
}

This will now return the payload without the shirtSize :

现在,这将返回不包含shirtSize的有效负载:

"player": {
        "name": "Pogba",
        "kit": [
            {
            "shoeSize": "medium"             }
         ]

    }

We can reverse this situation using the @include directive. It works as the opposite of the @skip directive. You can use it to reverse this skip action on the server by replacing the @skip directive with @include in the query.

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

结论 (Conclusion)

In this article, we have gone over the details of GraphQL queries. If you’d like to learn more about GraphQL, check out the GraphQL official docs. If you’d like to try making a project with GraphQL, try our How To Build and Deploy a GraphQL Server with Node.js and MongoDB on Ubuntu 18.04 tutorial.

在本文中,我们介绍了GraphQL查询的详细信息。 如果您想了解有关GraphQL的更多信息,请查阅GraphQL官方文档 。 如果您想尝试使用GraphQL创建项目,请尝试如何在Ubuntu 18.04教程上使用Node.js和MongoDB来构建和部署GraphQL服务器 。

翻译自: https://www.digitalocean.com/community/tutorials/understanding-queries-in-graphql

graphql 嵌套查询


http://www.niftyadmin.cn/n/3649199.html

相关文章

Python 和 VBScript 对文件编码-解码的方式 (Hex, Base64) 的疑问

本人目前的项目需要在Windows上用VBScript将一文件转换为二进制码存入数据库,再在Linux上用Python从数据库中读取并解码成图片。反复调试,发现微软和Python的转码标准不统一,导致了这种实现方式失败。若有哪位大侠是这方面的高手还请不吝赐教…

设置RecyclerView的位置(点击回到顶部)

1 隐藏和显示回到顶部按钮 假设有个RecylerView rvHome;有个adapter rvHome.setAdapter(new HomeFragmentAdapter(mContext, result)); GridLayoutManager manager new GridLayoutManager(mContext, 1); //设置滑动到哪个位置了的监听 manager.setSpanSizeLookup(new GridL…

IDEA数据加密算法实现

IDEA数据加密算法介绍之续篇,代码实现:http://blog.csdn.net/CXXSoft/archive/2006/08/23/1109279.aspx5、 源码://********************************************************************************IDEA数据加密算法1.0版本 *开发作者:…

Ubuntu 安装MySQL数据库,Windows 安装MySQL WorkBench进行远程管理,Django远程连接 手记

之前写过一篇《Ubuntu 安装Postgres数据库,Windows 安装PgAdmin进行远程管理,Django远程连接 手记》,这次使用MySQL实现相同的功能,上篇详见: http://blog.csdn.net/quicktest/article/details/7257715 Ubuntu通过SS…

Android科大语音输入和语音合成

第一步&#xff1a;导入libs包和jnilbs包 和 第二步&#xff1a;初始化(一定不能删除) SpeechUtility.createUtility(this, SpeechConstant.APPID "id"); 第三步&#xff1a;布局 <?xml version"1.0" encoding"utf-8"?> <LinearLay…

IDEA数据加密算法介绍

IDEA数据加密算法及实现作者&#xff1a;成晓旭IDEA对称数据加密算法&#xff0c;是我2000年刚毕业&#xff0c;工作需要进行数据加密时&#xff0c;学习、实现的第一个标准数据加密算法&#xff0c;并且此后就深深地迷上了数据加密这个方面&#xff0c;以后连续两年潜心学习和…

Python+Django+Ubuntu+Apache+Nginx架设服务器成功记

是看一个国外网站一步一步照着来的&#xff0c;复制过来 http://www.ventanazul.com/webzine/tutorials/django-deployment-guide-ubuntu Theres a time when every Django developer has to think about deployment scenarios, when I first did it last year I thought that…

Android实战技术:启动另一个App/apk中的Activity

Android提供了在一个App中启动另一个App中的Activity的能力&#xff0c;这使我们的程序很容易就可以调用其他程序的功能&#xff0c;从而就丰富了我们App的功能。比如在微信中发送一个位置信息&#xff0c;对方可以点击这个位置信息启动腾讯地图并导航。这个场景在现实中作用很…