为啥每个 GraphQL 查询/突变都有“两个名称”?

Posted

技术标签:

【中文标题】为啥每个 GraphQL 查询/突变都有“两个名称”?【英文标题】:Why are there "two names" for each GraphQL query/mutation?为什么每个 GraphQL 查询/突变都有“两个名称”? 【发布时间】:2019-08-11 14:48:56 【问题描述】:

我正在学习 GraphQL,有一个基本点让我感到困惑。我知道有一个简单的解释,但我找不到。具体来说,来自 Apollo 文档 (https://www.apollographql.com/docs/apollo-server/essentials/data.html#operation):

...为操作命名以便快速识别是有意义的 调试期间的操作或聚合类似操作 一起...操作可以通过在后面放置一个标识符来命名 查询或突变关键字,就像我们在此处使用 HomeBookListing 所做的那样:

query HomeBookListing    
     getBooks 
     title   
      
 

如果HomeBookListing 是查询的名称,那么getBooks 是什么?解析器的名称?

同样,当你将变量传递给查询时,为什么会有“两级”参数,像这样

mutation HomeQuickAddBook($title: String, $author: String = "Anonymous") 
  addBook(title: $title, author: $author) 
    title
  

那么,$title: String, $author: String = "Anonymous" 是传递给查询的变量,title: $title, author: $author 是传递给解析器的变量吗?

我当然可以记住模式,但我很想从概念上理解不同的部分在这里做什么。任何见解都非常感谢!

【问题讨论】:

我已经有一段时间没有接触graphql了,但如果我没记错的话:“什么是getBooks” - 解析器的名称,是的。它不是“查询的第二个名称”。你可以在它旁边有getProducts。它只是查询中的一个“字段”。 变异也一样:你为整个操作声明参数列表,那么操作的不同部分(addBook / addReview)将使用参数列表的不同子集。 @SergioTulentsev -- 谢谢。我认为这更多的是解析器本身中的单独“字段”,在服务器上,例如,您可以拥有const resolvers= Query: getBooks: async() => ...., getProducts: async() => ... 。我想这就是你所指的? 是的,确实如此。 【参考方案1】:

您可能会发现查看the spec 会有所帮助,但下面是一个简短的解释:

什么是操作?

GraphQL 中有三个操作(querymutationsubscription)。通常,一个 GraphQL 请求只包含这三个操作中的一个,它构成了请求的根,或者是进入架构其余部分的入口点。

每个操作都有一个与之关联的对象类型。按照惯例,这些类型被命名为QueryMutationSubscription,但它们的命名在功能上与您的模式无关。除了它们与特定操作的关联之外,这些对象类型并没有什么特别之处——每个对象类型都有一个namedescriptionfields,就像架构中的任何其他对象类型一样。我们将这三种类型统称为根操作类型

在您的示例中,query 根类型有一个名为getBooks字段。该字段根据与架构中的任何其他字段相同的规则进行解析。该字段唯一的特殊之处在于它位于根目录——在它之前没有解析过“父”字段。

操作名称是可选的,因为它们不会影响服务器返回的数据——它们通常用于调试目的(尽管一些客户端和工具使用它们来提供其他功能,所以拥有它们总是好的)。但是,为您的根操作类型指定至少一个字段名称是必要的,否则您的操作实际上不会做任何事情(即向服务器查询数据)。同样,这些字段是您进入架构其余部分的入口点和数据图的起点。

好的,但是变量呢?

根据规范:

变量必须在操作的顶部定义,并且在该操作的整个执行过程中都在范围内。

虽然我们没有用值初始化文档中的变量,但我们确实需要通过告诉 GraphQL 它是什么类型的变量来定义它。这允许 GraphQL 验证整个文档中变量的使用情况。例如,如果您将变量定义为 String,然后尝试在 Int 的输入字段中使用它,则验证将失败,并且您的请求甚至在执行之前就会崩溃。

变量总是被定义为操作定义的一部分——它们可以在文档中的任何地方使用,甚至可以多次使用。所以这里没有“两级参数”——一行是简单的定义,另一行是用法。

关于语义的一句话

尽管我们有一个规范,但围绕 GraphQL 的语言已经超越了其中概述的术语。 “查询”一词具有多种含义,您在查看各种文档和文章时可能会遇到这些含义。记住这些定义有助于避免混淆:

按照惯例,我们将与query 操作关联的根操作类型命名为Query 类型 非正式地,Query(即getBooks)上的字段通常被称为架构的“查询”(就像Mutation 类型上的字段通常被称为你的架构。 我们发送到服务器的完整请求字符串,包括整个操作和任何相关的fragments,正式称为文档。但是,我们通常将发出请求称为查询您的服务器。这导致文档本身经常被称为查询,无论操作是包含实际上是 query 还是像 mutation 这样的不同操作。

【讨论】:

以上是关于为啥每个 GraphQL 查询/突变都有“两个名称”?的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL 查询/突变的响应

为啥我在尝试从 C# 处理程序发布 GraphQL 查询时收到错误请求?

由 amplify 生成的 Graphql 查询运行良好,但由于身份验证规则而引发错误。为啥?

在graphql中突变后查询

graphQl突变查询不适用于变量

GraphQL - 如何在查询多个突变期间检索先前突变的 id