介绍怎么查询 GraphQL 服务。
字段:Fields
最简单的查询就是告诉 Graphql 你想要的字段是什么:
{
hero {
name
}
}查询结果:
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}注意看查询与结果的数据形状,它们是一致的。这是 GraphQL 最重要的一个特点,你会获取到期待的数据,服务器确切地知道客户端想要的字段。
name 字段的类型是 String,上面例子里,name 的值是 R2-D2,他是电影 Star Wars 里的人物。
上面这个例子,你要的是人物的 name,返回的是个字段串类型的数据。字段的值也可以是对象,你可以选择对象里的某些字段。GraphQL 的查询可以找到相关的对象还有它们的字段,这样客户端只需要用一个请求就可以提取大量相关的数据。如果是 REST,可能需要来回跑几次才能得到需要的数据。
查询:
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}结果:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}注意在上面这个例子里,friends 字段返回的是一组项目。单个项目还有列表项目的 GraphQL 查询,看起来都差不多。字段的类型在 Schema 里面有相关的标注。
参数:Arguments
给字段添加参数。
查询:
{
human(id: "1000") {
name
height
}
}结果:
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}在 REST 里面,你只能通过地址片断还有查询参数来传递参数。在 GraphQL 里面,每个字段,嵌套的对象都可以得到它自己的参数。你甚至可以给 Scalar 字段传递参数,可以在服务端就实现数据转换,不用单独在每个客户端去做这件事。
查询:
{
human(id: "1000") {
name
height(unit: FOOT)
}
}结果:
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 5.6430448
}
}
}参数可以是很多不同的类型。上面的例子用的是 Enumeration 类型,表示的是一组可选的选项(这里就是长度单位,可以是 METER 或 FOOT)。GraphQL 里面带着一些默认的类型,你也可以声明自定义的类型。
别名:Aliases
使用别名,可以重命名结果里的字段的名字。
查询:
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}结果:
{
"data": {
"empireHero": {
"name": "Luke Skywalker"
},
"jediHero": {
"name": "R2-D2"
}
}
}在上面,两个 hero 字段有冲突,但我们可以分别给它们起个别名,这样可以用一个请求就能同时得到这两个结果。
片断:Fragments
比如我们的应用里有个复杂的页面,可以让我们对比两个人物还有他们的朋友们。这里可以用 GraphQL 里的 fragments 创建可以重复使用的单元,fragments 的目的就是把应用里的经常用的复杂的数据需求分割成小块。
查询:
{
leftComparison: hero(episode: EMPIRE) {
...comparisonFields
}
rightComparison: hero(episode: JEDI) {
...comparisonFields
}
}
fragment comparisonFields on Character {
name
appearsIn
friends {
name
}
}结果:
{
"data": {
"leftComparison": {
"name": "Luke Skywalker",
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"friends": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "C-3PO"
},
{
"name": "R2-D2"
}
]
},
"rightComparison": {
"name": "R2-D2",
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}操作名:Operation name
之前我们在查询里忽略掉了 query 还有查询名,这是一种简单的写法。不过我们最好加上这些东西,可以让应用的代码更清晰一些。在执行 query 以外的操作,或者传递动态变量的时候,在查询里必须得加上 GraphQL 操作。
下面这个例子用了 query 作为操作类型,HeroNameAndFriends 作为操作名:
查询:
query HeroNameAndFriends {
hero {
name
friends {
name
}
}
}结果:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}操作类型可以是 query,mutation,或者 subscription 还有 describes。操作名可以用来描述查询操作,可以把它想成是个函数名,在调试应用的时候,操作名可以让我们更清楚问题出在了哪里。
变量:Variables
查询可能是动态的,比如根据下拉菜单的选择,搜索,或者一些过滤器的值动态执行查询。GraphQL 提供了一种方法,可以把查询中的动态值从查询里单独拿出来,放到一个独立的 dictionary 里面,这些动态值在 GraphQL 里叫变量(variables)。
使用变量,要做三件事:
- 用 $variableName 替换查询中的静态值。
- 声明 $variableName 是查询中可以接受的一个变量。
- 用独立的变量字典传递 variableName: value 。
查询:
query HeroNameAndFriends($episode: Episode) {
hero(episode: $episode) {
name
friends {
name
}
}
}变量:
{
"episode": "JEDI"
}结果:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}我们绝对不能直接从用户提供的值那里用插值的形式构建查询。变量也会说明查询中哪部分东西是动态的。
变量定义
在上面查询里的 $episode: Episode 就是变量的定义。它有点像是 typed 程序语言里的函数里面定义的参数。列出所有变量,用 $ 作用前缀,后面跟着它们的类型,上面的例子变量的类型就是 Episode。
声明的变量必须是 scalars,enums,或者 input object 类型。所以你想给字段传递一个复杂的对象,你需要知道哪种 input 类型跟服务端匹配。
变量定义可以是可选的,也可以是必须的。上面的例子里,在 Episode 后面没有 ! 号,所以它是可选的。不过如果你要传递变量的那个字段需要一个 non-null 参数,那么变量也会是必须的。
默认变量
在 type 声明的后面可以添加参数的默认值。
query HeroNameAndFriends($episode: Episode = "JEDI") {
hero(episode: $episode) {
name
friends {
name
}
}
}指令:Directives
使用指令,配合变量,可以动态地改变查询的结构。假设一个界面组件,有一个摘要视图跟详情视图,为这个组件构建一个查询:
query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}变量:
{
"episode": "JEDI",
"withFriends": false
}数据:
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}如果把变量中的 withFriends 的值设置成 true,那返回的查询结果应该是:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}GraphQL 有两个指令:
- @include(if: Boolean),如果参数的值是 true 才会在查询结果中包含字段。
- @skip(if: Boolean),参数的值如果是 true,忽略这个字段。
修改:Mutaions
修改数据用 mutation。
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}变量:
{
"ep": "JEDI",
"review": {
"stars": 5,
"commentary": "This is a great movie!"
}
}结果:
{
"data": {
"createReview": {
"stars": 5,
"commentary": "This is a great movie!"
}
}
}修改中的多个字段
跟查询一样,在一个修改中也可以包含多个字段,不过一个重要的区别是,查询字段并行执行,修改字段是一个接一个地被执行。
Inline Fragments
查询:
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
... on Droid {
primaryFunction
}
... on Human {
height
}
}
}变量:
{
"ep": "JEDI"
}结果:
{
"data": {
"hero": {
"name": "R2-D2",
"primaryFunction": "Astromech"
}
}
}Meta fields
查询:
{
search(text: "an") {
__typename
... on Human {
name
}
... on Droid {
name
}
... on Starship {
name
}
}
}结果:
{
"data": {
"search": [
{
"__typename": "Human",
"name": "Han Solo"
},
{
"__typename": "Human",
"name": "Leia Organa"
},
{
"__typename": "Starship",
"name": "TIE Advanced x1"
}
]
}
} GraphQL 


