GraphQL BEST PRACTICES:模式和类型

在本文中,您将了解有关GraphQL类型系统的所有信息,以及它如何描述可以查询哪些数据。由于GraphQL可以与任何后端框架或编程语言一起使用,我们将远离特定于实现的细节,只讨论概念。

Type system类型

如果您以前见过GraphQL查询,那么您知道GraphQL查询语言基本上是关于选择对象上的字段的。

Snip20191108_23

  1. 我们从一个特殊的“根”对象开始
  2. 我们选择hero字段
  3. 对于hero返回的对象,我们选择name和apparsIn字段

因为GraphQL查询的形状与结果非常匹配,所以您可以预测查询将返回什么,而不必知道服务器的很多信息。但是对我们需要的数据有一个准确的描述是很有用的-我们可以选择哪些字段?它们可能会返回哪些类型的对象?这些子对象上有哪些字段可用?这就是模式的来源。

每个GraphQL服务都定义了一组类型,这些类型完全描述了可以在该服务上查询的可能数据集。然后,当查询进入时,它们将根据该模式进行验证和执行。

Type language类型

GraphQL服务可以用任何语言编写。由于我们不能依赖特定的编程语言语法(如JavaScript)来讨论GraphQL模式,因此我们将定义自己的简单语言。我们将使用“GraphQL schema语言”——它类似于查询语言,允许我们以一种与语言无关的方式讨论GraphQL模式。

Object types and fields对象类型和字段

GraphQL模式最基本的组件是对象类型,它只表示一种可以从服务中获取的对象,以及它有哪些字段。在GraphQL模式语言中,我们可以这样表示它:

Snip20191108_24

这门语言可读性很强,但让我们来复习一下,这样我们就可以有一个共享的词汇表:
Character是一种GraphQL对象类型,这意味着它是一种包含一些字段的类型。架构中的大多数类型都是对象类型。
name和apparsin是字符类型上的字段。这意味着name和apparsin是惟一可以出现在对字符类型进行操作的GraphQL查询的任何部分中的字段。
String是一种内置的标量类型-这些类型可解析为单个标量对象,并且在查询中不能有子选择。稍后我们将更详细地讨论标量类型。
String!意味着该字段不可为空,这意味着GraphQL服务承诺在您查询该字段时总是给您一个值。在类型语言中,我们将用感叹号表示那些。
[Episode!]!表示事件对象的数组。因为它也是不可为空的,所以在查询appearsIn字段时,总是可以期望数组(包含零个或多个项)。从那一集开始!也是不可为空的,您始终可以期望数组中的每个项都是一个事件对象。
现在您知道了GraphQL对象类型是什么样子,以及如何阅读GraphQL类型语言的基础知识。

Arguments参数

GraphQL对象类型上的每个字段都可以有零个或多个参数,例如下面的长度字段:

Snip20191108_25所有参数都已命名。不像JavaScript和Python这样的语言,函数采用有序参数列表,GraphQL中的所有参数都是按名称传递的。在本例中,length字段有一个定义的参数unit。
参数可以是必需的,也可以是可选的。当一个参数是可选的时,我们可以定义一个默认值-如果没有传递unit参数,它将默认设置为METER。

The Query and Mutation types查询和复杂操作类型

架构中的大多数类型将只是普通对象类型,但架构中有两种类型是特殊的:

Snip20191108_26

每个GraphQL服务都有一个查询类型,可能有也可能没有变异类型。这些类型与常规对象类型相同,但它们是特殊的,因为它们定义了每个GraphQL查询的入口点。因此,如果您看到的查询如下所示:

Snip20191108_27

这意味着GraphQL服务需要一个带有hero和droid字段的查询类型:

Snip20191108_28

复杂操作以类似的方式工作-您在突变类型上定义字段,这些字段可用作查询中可以调用的根突变字段。
重要的是要记住,除了作为模式的“入口点”的特殊状态之外,查询和变异类型与任何其他GraphQL对象类型都是相同的,并且它们的字段的工作方式完全相同。

Scalar types标量类型

GraphQL对象类型有名称和字段,但在某些情况下,这些字段必须解析为一些具体的数据。这就是标量类型的来源:它们表示查询的叶。

Snip20191108_29

我们知道这一点是因为这些字段没有任何子字段-它们是查询的叶子。
GraphQL附带了一组现成的默认标量类型:
Int:有符号的32位整数。
Float:有符号的双精度浮点值。
String:一个UTF-8字符序列。
Boolean:真或假。
ID:ID标量类型表示一个唯一的标识符,通常用于重新获取对象或作为缓存的键。ID类型的序列化方式与字符串相同;但是,将其定义为ID表示它不打算为人可读。
在大多数GraphQL服务实现中,还可以指定自定义标量类型。

例如,我们可以定义日期类型:
scalar Date
然后由我们的实现来定义如何序列化、反序列化和验证该类型。例如,您可以指定日期类型应始终序列化为整数时间戳,并且您的客户机应该知道任何日期字段都应采用这种格式。

Enumeration types枚举类型

枚举类型也称为枚举,是一种特殊类型的标量,仅限于特定的允许值集。这允许您:
验证此类型的任何参数是否是允许的值之一
通过类型系统传达字段始终是有限值集之一
在GraphQL模式语言中,枚举定义可能是这样的:

Snip20191108_30

这意味着无论我们在什么地方使用我们的模式中的类型插曲,我们都希望它正是NEWHOPE、EMPIRE或JEDI之一。
注意,不同语言中的GraphQL服务实现将有自己的特定于语言的方式来处理枚举。在支持枚举作为一级公民的语言中,实现可能会利用这一点;在没有枚举支持的JavaScript之类的语言中,这些值可能会在内部映射到一组整数。但是,这些细节不会泄露给客户端,客户端可以完全按照枚举值的字符串名称进行操作。

Lists and Non-Null列表和非空

对象类型、标量和枚举是在GraphQL中只能定义的类型。但是,当您在模式的其他部分或查询变量声明中使用这些类型时,您可以应用其他类型修饰符来影响这些值的验证。让我们看一个例子:

Snip20191108_31

在这里,我们使用字符串类型并通过添加感叹号将其标记为非空!在类型名之后。这意味着我们的服务器总是希望为这个字段返回一个非空值,如果它最终得到一个空值,这个空值实际上会触发一个GraphQL执行错误,让客户机知道出了问题。

列表的工作方式与此类似:我们可以使用类型修饰符将类型标记为列表,这表示此字段将返回该类型的数组。在模式语言中,这是通过将类型包装在方括号中来表示的,[和]。它同样适用于参数,在参数中,验证步骤将需要该值的数组。

Snip20191108_32

Interfaces接口

与许多类型系统一样,GraphQL支持接口。接口是一种抽象类型,它包含一组特定的字段,类型必须包含这些字段才能实现接口。

Snip20191108_33 Snip20191108_34

当您希望返回一个或一组对象时,接口非常有用,但这些对象可能是几种不同类型的。

Union types联合类型

联合类型与接口非常相似,但它们不能在类型之间指定任何公共字段。

无论我们在模式中返回SearchResult类型,我们都可能得到Human、Droid或Starship。请注意,联合类型的成员必须是具体的对象类型;不能从接口或其他联合创建联合类型。

Snip20191108_36

在这种情况下,如果查询返回SearchResult联合类型的字段,则需要使用条件片段才能查询任何字段:

Snip20191108_35

“__ typename”字段解析为一个字符串,该字符串允许您在客户端上区分不同的数据类型。
此外,在这种情况下,由于人类和机器人共享一个公共接口(字符),您可以在一个位置查询它们的公共字段,而不必在多个类型中重复相同的字段:

Snip20191108_37

Input types输入类型

到目前为止,我们只讨论了将标量值(如枚举或字符串)作为参数传递到字段中。但也可以轻松地传递复杂的对象。这在突变的情况下尤其有价值,在这种情况下,您可能希望传入要创建的整个对象。在GraphQL模式语言中,输入类型看起来与常规对象类型完全相同,但是使用关键字input而不是type:

Snip20191108_38 Snip20191108_39

输入对象类型上的字段本身可以引用输入对象类型,但不能在架构中混合输入和输出类型。输入对象类型的字段上也不能有参数。

推荐文章

沪公网安备 31010702002009号