《GraphQL 名词 101:解析 GraphQL 的查询语法》【译】

The Anatomy of a GraphQL Query

GraphQL 日渐成为数据查询的主流标准之一,整个生态圈也蓬勃发展。本文则由浅入深地详细介绍基础的 GraphQL 格式与关键字,有助于初学者对于 GraphQL 的使用造成体系认知。git

GraphQL 日渐成为数据查询的主流标准之一。天天都会产生许多围绕这项技术发展的精彩讨论和新工具。GraphQL最棒的特性就是提供了一个丰富语言集来描述获取数据的API。可是用户该如何描述这种查询语言,以及GraphQL这项核心技术自己呢?let's talk!github

GraphQL specification解释了几乎全部出如今GraphQL查询语言中的概念,可是这篇文档实在是太长了,因此我准备在这篇博客中,借助一些具体的栗子来阐述其中一些最重要的概念,来帮助你成为GraphQL专家!至少在纸上谈兵方面 : )数据库

注! 这篇文章可不是GraphQL的入门读物。首先,你应该通读concepts on the graphql.org docs,而后经过Learn Apollo tutorial来学习使用GraphQL,最后当你想继续深刻了解这项技术时,再回到这里来吧!编程

最基本的GraphQL查询

你们一般会使用“查询”来称呼 GraphQL API 服务的一切。可是这样称呼会有太多东西混杂在一块儿了。咱们可能会把咱们跪求服务端的一系列行为称为一次查询、一次修改或者一次订阅,但我想“请求(request)”这个词可能更加复合HTTP通讯的概念,下面咱们先来定义一些最基础的概念:bash

  • GraphQL 请求体: 使用GraphQL语言定义的一个或多个操做或者数据片断,类型是字符串。
  • 操做: 能够被GraphQL执行引擎理解的一次查询、修改或订阅。

为了搞清楚GraphQL各类基本操做之间的区别,让咱们先来看一个简单的GraphQL请求体:服务器

GraphQL document

A simple query and its parts.

这个请求体显示了GraphQL的主要构建块,它指定了你尝试获取的数据。网络

  • 字段(Fields):客户端请求的数据单元,最后做为JSON响应数据中的一个字段。请注意,它们始终称为“字段”,不管它们所在的层次有多深。在你的查询中,对根节点字段的处理和最底层字段应该是同样的。
  • 参数(Arguments):一组与特定字段关联的键值对。这些参数会跟它们相关的字段一块儿被传递到服务器端执行,并影响服务器对字段的处理方式。如上面的示例,参数能够是字面量,接下来还有参数做为变量形式的栗子。请注意,参数能够显示在任何字段中,即便是嵌套层次很深的字段。

为了让你以很是简洁的形式定义一个GraphQL查询,上面的栗子是GraphQL的一种很是简单的形式。可是在GraphQL操做中三种可选的部分都没有在上述栗子中使用。若是你不只仅是用GraphQL执行查询操做,或是但愿传递动态变量到GraphQL查询中,你就须要利用到这些新的GraphQL特性。数据结构

这里刚好有一个包含了全部可选部分的栗子:编程语言

A more detailed query and its parts.

A more detailed query and its parts.
  • 操做类型(Operation type):共三种类型:查询(query)、更新(mutation)、订阅(subscription)。它描述了你试图进行何种操做。然而这些看起来意思很接近的操做,GraphQL服务器处理它们时仍是会有一些不一样。
  • 操做名称(Operation name):为了方便调试和服务端打日志,最好给你的查询赋予语义化的命名。这样,不管你是在网络日志中或者GraphQL服务器上发现错误,你均可以经过名字很轻松的在代码库中定位问题,而不是靠猜想(相似的工具备 Apollo Optics)。能够把操做名称想象成你最喜欢的编程语言中,一个语义化的函数名。
  • 变量定义(Variable definitions):当客户端向GraphQL服务器发送查询时,会存在查询文档不变,当某些字段会动态变化的状况。这些就是查询中的变量。由于GraphQL是静态类型的,它能够实时验证你是否传递了正确的变量。这正是你声明变量类型时所计划提供的能力。

变量使用特定的序列化协议(在目前的 GraphQL 服务实现中,一般是使用JSON )经过查询文档独立传输。下面是一个变量对象在查询文档中的示例: 函数

An example variables object.

An example variables object.
能够看到,这里的关键是变量名称须要与变量定义所匹配,其名称是`Episode`枚举中的一个成员。
  • 变量(Variables): 它是传递给GraphQL operation的值的字典,提供了operation的动态入参。

这里有一个在谈及Graph的技术意义时很重要,却不常被说起的核心概念——花括号之间的全部东西叫什么?

*选择集(selection set)*是一个会在GraphQL 文档中常常出现的概念,它赋予了GraphQL递归的特性,容许你获取嵌套形式的数据。

  • 选择集(selection set):它是一次operation中须要的一组字段,或者被嵌套在其余的字段中。GraphQL查询必须包含一个标识选择集的字段,且该字段返回的是对象类型,选择集不能设置在返回值是标量类型(Scalar Types)的字段上,例如Int或者String

片断(Fragments)

当开始介绍片断(fragments)以后,GraphQL 将变得更增强大。它带来了一系列新的概念。

  • 片断定义(Fragment definition):定义一个片断是GraphQL文档的一部分。为了区别于咱们下面会介绍的内联片断,它有时候也被称为片断命名

Fragments

A fragment definition and its parts.
  • **片断名称(Fragment name): **片断(fragments )名在GraphQL文档中必须是惟一的。这个名称用于在操做(operations)或者其余片断(fragments )引用片断(fragments )。就像操做(operations)名称同样,片断名也能用于服务端日志调试,因此咱们推荐使用明确且有意义的片断(fragments )名。若是你使用了正确的片断(fragments )名,在优化数据获取时,你可以很好的追踪你的代码。
  • 类型条件(Type condition): GraphQL操做老是开始于查询、修改或者订阅schema中的类型,可是片断(fragments )可以用于任一选择,因此为了将校验片断(fragments )与校验schema独立开,你须要指定片断(fragments )可以使用的类型,而这就是类型条件(Type condition)的做用。

就像操做(operations)同样,片断也选择集,使用起来也跟在操做(operations)中使用选择集同样。

在你的操做(operations)中使用片断(fragments )

片断(fragments )只有在操做(operations)中使用才能发挥出做用。片断是 GraphQL 的主要组合数据结构,经过片断能够重用重复的字段选择,减小 query 中的重复内容。接下来咱们将介绍使用片断(fragments )的两种方式:

fragments

  • **片断扩展运算符(Fragment spread): ** 当你在操做或者其余片断中使用片断时,你能够将片断名置于...以后来表示片断。例如没有片断时须要这样编写 query:
query noFragments {
  user(id: 4) {
    friends(first: 10) {
      id
      name
      profilePic(size: 50)
    }
    mutualFriends(first: 10) {
      id
      name
      profilePic(size: 50)
    }
  }
}
复制代码

query 中存在下列重复的选择集合:

{
  id
  name
  profilePic(size: 50)
}
复制代码

能够用片断简化为:

query withFragments {
  user(id: 4) {
    friends(first: 10) {
      ...friendFields
    }
    mutualFriends(first: 10) {
      ...friendFields
    }
  }
}

fragment friendFields on User {
  id
  name
  profilePic(size: 50)
}
复制代码

使用片断时须要加上 ... 操做符表示展开片断内容,这称为片断扩展运算符(fragment spread),它能够用在任何选择集(selection set)中,用以匹配片断的类型条件。

  • 内联片断(Inline fragment): 若是你仅仅是想执行一些依赖结果类型的字段,却不想把它们抽离成独立的定义,你可使用内联片断( inline fragment)。它使用起来跟独立的命名片断同样,可是写在查询的内部。有一点不一样的是,对于内联片断来讲类型条件(type condition)不是必须的,能够像使用指令同样来使用它,接下来咱们会演示指令(directive)的栗子。

指令(Directives)

指令是独立于GraphQL server以外的一个附加功能。指令不会对结果的值产生影响,可是会影响哪些结果会被返回,也许还会影响这些结果是如何被执行的。指令能够出如今查询的任何地方,但在这篇文章中咱们只关注当前GrahpQL文档所描述的skip(忽略)include(包括) 两个指令。

Directives

You probably wouldn’t usually put all of these in one query, but it’s the easiest way to demonstrate.
你能在上文厨房水槽的栗子中使用指令`skip` 和 `include`。`include` 指令表示只有在 if 参数为 true 时才引入片断表示的字段。`skip` 指令表示在 if 参数为 true 时忽略片断中的字段。因为指令的语法至关灵活,咱们能够利用它来给GraphQL添加更多的特性,而不是使用语法解析或者引入更复杂的工具的方式。
  • **指令(Directive): ** 在字段、片断或者查询中的一个注释,include 指令表示只有在 if 参数为 true 时才引入片断表示的字段。skip 指令表示在 if 参数为 true 时忽略片断中的字段。
  • 指令参数(Directive arguments): 与字段参数相似,只不过它们是被执行引擎处理,而不是传递给字段解析器(field resolver)。

总结

GraphQL 是在应用层对业务数据模型的抽象,是对数据请求定制的 DSQL,它解除了接口和数据之间的绑定,对业务数据结构作了抽象和整理,业务逻辑中的数据依赖于底层数据库结构,而且能够由具体业务场景来定制,不一样的业务场景只要基于一样一套基础业务数据模型就能够获得复用,在我看来,这才是 GraphQL 带来的最大改变和收益。 目前GitHub整站API已迁移GraphQL,淘宝也在生成环境有所实践。

参考文档:


《IVWEB 技术周刊》 震撼上线了,关注公众号:IVWEB社区,每周定时推送优质文章。

相关文章
相关标签/搜索