本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
GraphQL 支持很多不同的类型。正如您在上一节中看到的一样,类型定义数据的形状或行为。它们是 GraphQL 架构的基本构建块。
类型可以分为输入和输出。输入是允许作为特殊对象类型(Query
、Mutation
等)的参数传入的类型,而输出类型严格用于存储和返回数据。下面列出了类型及其分类的列表:
-
对象:对象包含描述实体的字段。例如,一个对象可能类似于
book
,其中包含描述其特性的字段,如authorName
、publishingYear
等。它们严格来说是输出类型。 -
标量:这些是基元类型,如整数、字符串等。它们通常分配给字段。以
authorName
字段为例,可以为其分配String
标量以存储名称,例如“John Smith”。标量可以是输入类型和输出类型。 -
输入:输入允许您传递一组字段以作为参数。它们的结构与对象非常相似,但可以将其作为特殊对象的参数传递。输入允许您在其范围内定义标量、枚举和其他输入。输入只能是输入类型。
-
特殊对象:特殊对象执行状态更改操作,并完成服务的大部分繁重工作。共有三种特殊对象类型:查询、变更和订阅。查询通常获取数据;变更处理数据;订阅在客户端和服务器之间打开并保持双向连接以进行持续通信。鉴于其功能,特殊对象既不是输入,也不是输出。
-
枚举:枚举是预定义的合法值列表。如果调用枚举,则枚举值只能是其范围内定义的值。例如,如果您使用一个名为
trafficLights
的枚举以描述交通信号列表,它可能具有redLight
和greenLight
等值,但不能具有purpleLight
值。真正的交通信号灯只有那么多信号,因此,您可以使用枚举定义它们,并在引用trafficLight
时强制使它们成为唯一的合法值。枚举可以是输入类型和输出类型。 -
联合/接口:联合允许您根据客户端请求的数据在请求中返回一个或多个内容。例如,如果您使用具有
title
字段的Book
类型以及具有name
字段的Author
类型,您可以在这两种类型之间创建联合。如果您的客户端希望在数据库中查询“Julius Caesar”,则联合可能会从Book
title
返回 Julius Caesar(威廉·莎士比亚的戏剧),并从Author
name
返回 Julius Caesar(Commentarii de Bello Gallico 的作者)。联合只能是输出类型。接口是对象必须实施的字段集。这有点类似于 Java 等编程语言中的接口,您必须实施接口中定义的字段。例如,假设您创建了一个名为
Book
的接口,其中包含一个title
字段。假设您后来创建了一个名为Novel
的类型,该类型实施Book
。Novel
必须包含一个title
字段。不过,Novel
可能还包含接口中不包含的其他字段,例如pageCount
或ISBN
。接口只能是输出类型。
以下几节介绍了每种类型在 GraphQL 中的工作方式。
对象
GraphQL 对象是您在生产代码中看到的主要类型。在 GraphQL 中,您可以将对象视为不同字段的分组(类似于其他语言中的变量),每个字段由可以保存值的类型(通常是标量或另一个对象)定义。对象表示可以从服务实施中检索/处理的数据单元。
对象类型是使用 Type
关键字声明的。让我们稍微修改一下架构示例:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
此处的对象类型是 Person
和 Occupation
。每个对象具有自己的字段和自己的类型。GraphQL 的一项功能是,能够将字段设置为其他类型。您可以看到 Person
中的 occupation
字段包含 Occupation
对象类型。我们可以建立这种关联,因为 GraphQL 仅描述数据,而不描述服务实施。
标量
标量本质上是保存值的基元类型。在 AWS AppSync 中,具有两种类型的标量:默认 GraphQL 标量和 AWS AppSync 标量。标量通常用于存储对象类型中的字段值。默认 GraphQL 类型包括 Int
、Float
、String
、Boolean
和 ID
。让我们再次使用上一示例:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
挑出 name
和 title
字段,两者都包含 String
标量。Name
可能返回类似于 "John Smith
" 的字符串值,title 可能返回类似于 "firefighter
" 的值。一些 GraphQL 实施还支持使用 Scalar
关键字并实施类型行为的自定义标量。不过,AWS AppSync 目前不支持自定义标量。有关标量的列表,请参阅 AWS AppSync 中的标量类型。
输入
由于输入和输出类型概念,在传入参数时存在特定的限制。通常需要传入的类型(尤其是对象)受到限制。您可以使用输入类型绕过该规则。输入是包含标量、枚举和其他输入类型的类型。
输入是使用 input
关键字定义的:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
input personInput {
id: ID!
name: String
age: Int
occupation: occupationInput
}
input occupationInput {
title: String
}
正如您看到的一样,我们可以使用模仿原始类型的单独输入。这些输入通常在您的字段操作中使用,如下所示:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
input occupationInput {
title: String
}
type Mutation {
addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
请注意,我们仍然可以传递 occupationInput
(替代 Occupation
)以创建 Person
。
这只是输入的一种场景。它们不一定需要以 1:1 的方式复制对象;在生产代码中,您很可能不会像这样使用该参数。一种利用 GraphQL 架构的很好做法是,仅定义需要作为参数输入的内容。
此外,可以在多个操作中使用相同的输入,但我们不建议这样做。理想情况下,每个操作应包含自己的唯一输入副本,以防架构的要求发生变化。
特殊对象
GraphQL 为特殊对象保留一些关键字,这些对象定义架构如何检索/处理数据的一些业务逻辑。最多可以在架构中包含其中的关键字之一。它们充当客户端对 GraphQL 服务运行的所有请求的数据的入口点。
也可以使用 type
关键字定义特殊对象。尽管它们的使用方式与常规对象类型不同,但它们的实施非常相似。
查询与 GET
操作非常相似,因为它们执行只读获取以从源中获取数据。在 GraphQL 中,Query
定义向您的服务器发出请求的客户端的所有入口点。在您的 GraphQL 实施中始终具有一个 Query
。
以下是我们在以前的架构示例中使用的 Query
和修改的对象类型:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
type Query {
people: [Person]
}
我们的 Query
包含一个名为 people
的字段,该字段从数据来源中返回 Person
实例列表。假设我们需要更改应用程序的行为,现在我们需要返回仅包含 Occupation
实例的列表以用于某些单独的用途。我们可以直接将其添加到查询中:
type Query {
people: [Person]
occupations: [Occupation]
}
在 GraphQL 中,我们可以将查询视为单一请求来源。正如您看到的一样,这可能比使用不同终端节点(.../api/1/people
和 .../api/1/occupations
)实现相同目标的 RESTful 实施简单得多。
假设我们具有该查询的解析器实施,我们现在可以执行实际的查询。虽然 Query
类型存在,但我们必须明确调用该类型,才能在应用程序的代码中运行。可以使用 query
关键字完成该操作:
query getItems {
people {
name
}
occupations {
title
}
}
正如您看到的一样,该查询命名为 getItems
并返回 people
(Person
对象列表)和 occupations
(Occupation
对象列表)。在 people
中,我们仅返回每个 Person
的 name
字段,同时返回每个 Occupation
的 title
字段。响应可能如下所示:
{
"data": {
"people": [
{
"name": "John Smith"
},
{
"name": "Andrew Miller"
},
.
.
.
],
"occupations": [
{
"title": "Firefighter"
},
{
"title": "Bookkeeper"
},
.
.
.
]
}
}
该示例响应说明了数据如何遵循查询的形状。检索的每个条目在该字段的范围内列出。people
和 occupations
是作为单独的列表返回的。虽然这很有用,但修改查询以返回人员姓名和职业的列表可能会更方便:
query getItems {
people {
name
occupation {
title
}
}
这是合法的修改,因为我们的 Person
类型包含 Occupation
类型的 occupation
字段。在 people
范围内列出时,我们将返回每个 Person
的 name
及其按 title
关联的 Occupation
。响应可能如下所示:
}
"data": {
"people": [
{
"name": "John Smith",
"occupation": {
"title": "Firefighter"
}
},
{
"name": "Andrew Miller",
"occupation": {
"title": "Bookkeeper"
}
},
.
.
.
]
}
}
我们的架构示例中没有提到的一件事是,还必须在 schema
根中定义您的特殊对象类型。因此,当您在 AWS AppSync 中导出架构时,它可能如下所示:
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
.
.
.
type Query {
# code goes here
}
type Mutation {
# code goes here
}
type Subscription {
# code goes here
}
枚举
枚举是特殊标量,它限制类型或字段可能具有的合法参数。这意味着每次在架构中定义枚举时,其关联类型或字段仅限于枚举中的值。枚举被序列化为字符串标量。请注意,不同的编程语言可能以不同的方式处理 GraphQL 枚举。例如,JavaScript 没有本机枚举支持,因此,枚举值可能会映射到整数值。
枚举是使用 enum
关键字定义的。示例如下:
enum trafficSignals {
solidRed
solidYellow
solidGreen
greenArrowLeft
...
}
在调用 trafficLights
枚举时,参数只能是 solidRed
、solidYellow
、solidGreen
等。通常使用枚举描述具有不同但有限数量的选项的内容。
联合/接口
请参阅 GraphQL 中的接口和联合。