GraphQL 基础
GraphQL是一个API查询语言,它能够对现有API中的数据进行完整的和可理解的描述。
使客户端一次查询就能够准确的获取到想要的所有字段,不多也不少。
这样随着时间的推移,使得API开发升级更容易。 GraphQL也提供了强大的开发工具,协助我们在开发过程中更方便的写查询语句。
官网入口
Queries and Mutations 查询和修改
Feilds 字段
GraphQL可以在查询中列出需要的字段,要求服务端返回这些字段:
1 | { |
如上面的查询,会获得如下返回:
1 | { |
查询语句里可以写注释:
1 | { |
Arguments 参数
GraphQL查询支持传参数:
1 | { |
Alias 别名
查询语句支持给字段取别名,这样做就可以根据不同的参数,获取分别同一个字段:
1 | { |
Fragments 片段
代码片段, 可以把一些公共的查询提取出来, 取个名字, 到处复用:
1 | { |
引用代码片段: ...fragmentName
Operation Name 操作名
操作可以取名:
1 | query HeroComparison($first: Int = 3) { |
推荐给操作取名, 方便定位问题,打印日志
Operation Types 操作类型
query, mutation, subscription, describes
简写语法 可以省略 operation type。 默认是 query, 这种情况就不能定义 operation name 和参数了。
Variables 变量
变量 解决的是 “手工String插值” 的问题
在 Operation Name’s Arguments里定义变量, ($varName: Types). 变量名以 $ 符号开头, 冒号后跟变量类型
然后通过单独的变量字典(通常是json)传递变量值: {“varName”: “1111”}。
变量可以定义为 可选的 或者 必须的(在变量类型后跟 ! 表示 必须的),如果如果接收变量的字段需要非空参数, 那变量隐式为必须的。
默认值: 定义变量的时候可以设置默认值, 通过 = 号
Directives 指令
指令(结合变量) 解决的是 变量 查询结构的问题
指令 以 @ 符号开头, 跟在字段或者片断 后面。
目前 GraphQL 规范明确包含两个指令: 所有的 GraphQL 兼容服务端都必须支持:
@include(if: Boolean)
参数为true
的时候包含此字段@skip(if: Boolean)
参数为true
的时候跳过此字段
Mutations 修改
通过 mutation operation type 来执行修改, 修改也会返回修改里的字段
多个修改是串行的, 多个查询是并行的
Inline Fragments 内嵌片段
主要是解决字段是接口或者联合 类型时, 根据值的实际类型,获取不同信息
Meta fields 元字段
内嵌片段判断实际类型时,如果不知道字段具体有哪些实际类型, 可以通过 __typename
元字段 来获取每个值的实际类型。
GranphQL定义了一些元字段, https://graphql.org/learn/introspection/
Schemas and Types 结构和类型
Type System
The exact description of the data we can ask for.
我们能请求的数据 的准确描述,比如:可能选择的字段,返回的是哪种对象,这些子对象有哪些可用字段等。 这些就是 schema
解决的问题。
GraphQL 服务端 都会定义它能查询到的所有类型, 以及关于这些类型的完整描述。当查询进来的时候, 服务端会根据 schema 来校验和执行查询。
Type language
GraphQL schema language
Object types and fields
Object 类型是组成 schema 的最基本组件, 它会包含一些字段。 定义:
1 | type Character { |
type
关键字定义了一个叫Character
的对象类型, 意味着这个类型会拥有一些字段, schema中的大多数类型,都会是对象类型。name
和appearsIn
是Character
对象类型的字段,意思是在GraphQL query 语句里, 这两个字段只能出现在 操作Character
类型时。String
是内置的 scalar types,scalar types 就不能再有子字段了。String!
表示此字段是 non-null 的, 服务端返回的这个字段一定有值[Episode!]!
表示 这是一个Episode
对象数组。外层的!
表示此这数组是 non-null的(可以是空数组), 里面的!
表示数组的每个元素都是 non-null 的
Arguments 参数
GraphQL 对象类型的所有字段, 都可以有0个或多个参数, 比如下面的 length
字段:
1 | type Starship { |
所有参数都要命名,传参是根据名字, 不按顺序。 参数可以是可选的, 也可以是必须的; 可选参数可以有默认值。比如上例中 unit
参数的默认值是METER
。
The Query and Mutation types
schema 中多数类型都是常规的对象类型,但是有两个特殊的:
1 | schema { |
每个 GraphQL 服务都有query
类型,可能有mutation
类型, 他们和普通对象类型一样的, 唯一特殊的一点是他们定义了每个GraphQL查询的入口。
对于 query 查询中用到的所有字段, 在服务端的 Query
类型定义里都必须要出现,
比如下面这个query:
1 | query { |
那在服务端Query
类型的定义里,就至少需要有如下字段:
1 | type Query { |
Scalar types 标量类型
标量就不能再有子字段了,是不可再的拆分的类型, 是查询的叶子节点。GraphQL的内置标量有:
Int
: 有符号32位整型Float
: 有符号双精度浮点数String
: UTF-8 字符串Boolean
:true
orfalse
ID
:表示唯一标识, 通常用来获取对象, 或者做为缓存的key,ID类型通过序列化为String, 定义为ID类型表示人类不可读。
多数GraphQL 服务实现里, 都支持处定义标量, 比如定义一个名叫Date
的标量类型:
1 | scalar Date |
然后由GraphQL 服务实现 来定义 这个类型的序列化、反序列化和验证。
Enumeration types 枚举
枚举是特殊的标量, 只允许它定义的几个值。比如定义一个叫Episode
的枚举:
1 | enum Episode { |
Lists and Non-Null 集合和 Non-null
没有什么特殊的, 就是传统意义上的集合和 Non-null。
Interfaces 接口
接口是抽象类型,实现它的子类型, 必须包含接口中定义的字段。 定义一个Character
接口:
1 | interface Character { |
再定义两个子类型Human
和Droid
:
1 | type Human implements Character { |
Union types 联合类型
联合类型与接口非常相似,但是它不能指定类型之间的任何公共字段。
1 | union SearchResult = Human | Droid | Starship |
注意,联合类型的成员必须是具体的对象类型;不能是接口或其他联合类型。
查询的时候通过需要使用 Inline Fragment
来处理接口和联合类型。
Input types 输入类型
输入类型在修改时特别有用,可以用来把整个对象做为参数传递。定义input type:
1 | input ReviewInput { |
使用:
1 | mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { |
输入对象类型上的字段本身可以引用输入对象类型,但在schema中不能混合输入和输出类型,输入对象类型的字段
也不能有参数。