作者选择了自由开源基金作为为捐赠而写计划的一部分来接受捐赠。
介绍
GraphQL是促进前端与数据源通信的现代解决方案。GraphQL实现的所有细节和功能都在GraphQL模式中阐明。为了编写一个功能正常的GraphQL模式,您必须了解GraphQL类型系统。
在本文中,您将了解GraphQL类型:五种内置标量类型,枚举,列表和非空包装类型,对象类型,以及与它们配合使用的抽象接口和联合类型。您将审查每种类型的示例,并学习如何使用它们来构建完整的GraphQL模式。
先决条件
为了充分利用本教程,您应该具备以下知识:
- 对GraphQL基本概念的理解,这些概念在GraphQL简介中有介绍。
- A GraphQL environment, an example of which can be found in How to Set Up a GraphQL API Server in Node.js.
标量类型
GraphQL模式中的所有数据最终都会解析为各种标量类型,这些类型代表原始值。GraphQL响应可以表示为一棵树,而标量类型是树末端的叶子。响应中可以有多个嵌套级别,但最后一级始终会解析为标量(或枚举)类型。GraphQL带有五种内置标量类型:Int
、Float
、String
、Boolean
和ID
。
Int
Int
是一个带符号的 32 位非小数数值。它是一个带符号(正数或负数)的整数,不包括小数。带符号 32 位整数的最大值是 2,147,483,647
。这是用于数值数据的两种内置标量之一。
Float
A Float
is a signed double-precision fractional value. It is a signed (positive or negative) number that contains a decimal point, such as 1.2
. This is the other built-in scalar used for numerical data.
String
A String
is a UTF-8 character sequence. The String
type is used for any textual data. This can also include data like very large numbers. Most custom scalars will be types of string data.
Boolean
A Boolean
is a true
or false
value.
ID
ID
是一个唯一标识符。这个值总是被序列化为一个字符串,即使这个 ID
是数字。一个 ID
类型可能常用一个 通用唯一标识符 (UUID) 来表示。
自定义标量
除了这些内置标量之外,scalar
关键字可用于定义自定义标量。您可以使用自定义标量创建具有额外服务器级验证的类型,例如 Date
、Time
或 Url
。以下是定义新 Date
类型的示例:
scalar Date
服务器将知道如何处理与此新类型的交互,使用 GraphQLScalarType
。
枚举类型
Enum 类型,也称为 Enumerator 类型,描述了一组可能的值。
在 如何使用 GraphQL 管理数据 系列的其他教程中使用幻想游戏 API 主题,您可能会为游戏角色的 Job
和 Species
制作一个 enum
,其中包含系统将接受的所有值。枚举是用 enum
关键字定义的,如下所示:
"The job class of the character."
enum Job {
FIGHTER
WIZARD
}
"The species or ancestry of the character."
enum Species {
HUMAN
ELF
DWARF
}
这样,就保证了一个角色的Job
是FIGHTER
或WIZARD
,永远不会意外地变成"purple"
或其他随机字符串,如果你使用了String
类型而不是自定义枚举的话,这种情况是可能发生的。按照约定,枚举通常以全大写字母编写。
枚举也可以用作参数的可接受值。例如,你可以创建一个Hand
enum
来表示武器是单手(像短剑)还是双手(像重型斧头),并使用它来确定是否可以装备一把或两把:
enum Hand {
SINGLE
DOUBLE
}
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
hand: Hand
}
type Query {
weapons(hand: Hand = SINGLE): [Weapon]
}
Hand
enum
已经声明了SINGLE
和DOUBLE
作为值,weapons
字段上的参数默认值为SINGLE
,这意味着如果没有传递参数,它将退回到SINGLE
。
非空类型
你可能注意到,在内置标量列表中,null
或undefined
,许多语言都认为是原始类型的常见类型,不在其中。Null在GraphQL中确实存在,表示没有值。
所有GraphQL中的类型默认都是可空的,因此null
对于任何类型都是有效的响应。为了使值为必需,必须将其转换为带有感叹号的GraphQL 非空类型。非空被定义为类型修饰符,这些类型用于修改其所指的类型。例如,String
是可选(或可空)字符串,而String!
是必需(或非空)字符串。
列表类型
A List type in GraphQL is another type modifier. Any type that is wrapped in square brackets ([]
) becomes a List type, which is a collection that defines the type of each item in a list.
例如,定义为[Int]
的类型将是Int
类型的集合,而[String]
将是String
类型的集合。非空和列表可以一起使用,使类型既必需又定义为列表,例如[String]!
。
对象类型
如果GraphQL标量类型描述了层次结构GraphQL响应末端的“叶子”,那么对象类型描述了中间的“分支”,并且几乎在GraphQL模式中的每个地方都是对象类型。
对象由一系列命名字段(键)和每个字段将解析为的值类型组成。对象是用type
关键字定义的。必须至少定义一个或多个字段,并且字段不能以两个下划线(__
)开头,以避免与GraphQL内省系统冲突。
在GraphQL Fantasy Game API示例中,您可以创建一个Fighter
对象来表示游戏中的一种角色:
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
}
在这个例子中,Fighter
对象类型已经被声明,并且它有四个命名字段:
id
产生一个非空ID
类型。name
产生一个非空String
类型。level
产生一个Int
类型。active
产生一个非空Boolean
类型。
在声明之上,您还可以使用双引号添加注释,就像这个例子中的"具有直接战斗能力和力量的英雄"
。这将显示为类型的描述。
在这个例子中,每个字段都解析为标量类型,但对象字段也可以解析为其他对象类型。例如,您可以创建一个Weapon
类型,并且GraphQL模式可以被设置为Fighter
上的weapon
字段将解析为一个Weapon
对象:
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
}
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
weapon: Weapon
}
对象也可以嵌套到其他对象的字段中。
根操作类型
有三个特殊的对象,它们充当GraphQL模式的入口点:Query(查询)、Mutation(变更)和Subscription(订阅)。这些被称为根操作类型,并遵循与任何其他对象类型相同的规则。
关键字schema
表示进入GraphQL模式的入口点。您的根Query、Mutation和Subscription类型将位于根schema
对象上:
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
Query类型在任何GraphQL模式上都是必需的,表示读取请求,类似于REST API的GET
。以下是一个根Query
对象的示例,返回Fighter
类型的列表:
type Query {
fighters: [Fighter]
}
Mutations表示写入请求,类似于REST API中的POST
、PUT
或DELETE
。在以下示例中,Mutation
具有一个带有命名参数input
的addFighter
字段:
type Mutation {
addFighter(input: FighterInput): Fighter
}
最后,订阅对应于事件流,可与Web应用程序中的Websocket结合使用。在GraphQL Fantasy API中,它可能用于随机战斗遭遇,如下所示:
type Subscription {
randomBattle(enemy: Enemy): BattleResult
}
请注意,schema
入口点在某些GraphQL实现中通常被抽象化。
字段参数
GraphQL对象的字段本质上是返回值的函数,并且它们可以接受任何函数一样的参数。字段参数由参数名称后跟类型定义。参数可以是任何非对象类型。在此示例中,Fighter
对象可以通过id
字段进行过滤(该字段解析为非空ID
类型):
type Query {
fighter(id: ID!): Fighter
}
此特定示例适用于从数据存储中获取单个项目,但参数也可用于过滤、分页和其他更具体的查询。
接口类型
与对象类型类似,抽象接口类型由命名字段及其关联值类型列表组成。接口看起来和遵循对象的所有相同规则,但用于定义对象实现的子集。
到目前为止,在你的模式中,你有一个Fighter
对象,但你可能还想要创建一个Wizard
,一个Healer
,以及其他一些对象,它们将共享许多相同的字段,但也有一些差异。在这种情况下,你可以使用接口来定义它们共有的字段,并创建实现了该接口的对象。
在下面的示例中,你可以使用interface
关键字创建一个BaseCharacter
接口,其中包含每种类型角色都将拥有的所有字段:
"A hero on a quest."
interface BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job
}
每种角色类型都将拥有id
、name
、level
、species
和job
字段。
现在,想象一下你有一个Fighter
类型和一个Wizard
类型,它们拥有这些共享字段,但Fighters
使用Weapon
,而Wizards
使用Spells
。你可以使用implements
关键字来将每个类型标记为BaseCharacter
的实现,这意味着它们必须拥有来自创建的接口的所有字段:
"A hero with direct combat ability and strength."
type Fighter implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
weapon: Weapon
}
"A hero with a variety of magical powers."
type Wizard implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
spells: [Spell]
}
Fighter
和Wizard
都是BaseCharacter
接口的有效实现,因为它们具有所需的字段子集。
Union Type
另一种可以与对象一起使用的抽象类型是\texttt{Union}类型。使用\texttt{union}关键字,您可以定义一个包含一系列对象的类型,这些对象都可以作为响应。
使用前一节中创建的接口,您可以创建一个\texttt{Character}联合体,将字符定义为\texttt{Wizard}或\texttt{Fighter}:
union Character = Wizard | Fighter
等号字符(\texttt{=})设置了定义,而竖线字符(\texttt{|})则作为\texttt{OR}语句的功能。请注意,联合体必须由对象或接口组成。标量类型在联合体中无效。
现在,如果您查询字符列表,它可以使用\texttt{Character}联合体,并返回所有\texttt{Wizard}和\texttt{Fighter}类型。
结论
在这个教程中,你学习了许多定义了 GraphQL 类型系统 的类型。最基本的类型是标量类型,它们是作为模式树上叶子的值,包括 Int
、Float
、String
、Boolean
、ID
,以及 GraphQL 实现决定创建的任何自定义标量。枚举是有效常量值的列表,当你需要比简单声明为 String
更多控制响应时可以使用它们,它们也是模式树上的叶子。列表和非空类型被称为类型修饰符,或包装类型,它们可以分别定义其他类型为集合或必需。对象是模式树的分支,几乎在 GraphQL 模式中的一切都是对象类型,包括 query
、mutation
和 subscription
入口点。接口和联合类型是抽象类型,对于定义对象非常有帮助。
要进一步学习,你可以通过阅读 如何在 Node.js 中设置 GraphQL API 服务器 教程来练习创建和修改 GraphQL 模式,以便拥有一个可用的 GraphQL 服务器环境。
Source:
https://www.digitalocean.com/community/conceptual-articles/understanding-the-graphql-type-system