[TOC]
#### 语法
![](https://box.kancloud.cn/59d2566e497f38cad0ed2ecb7453d7db_300x165.jpg)
#### 定义
`GraphQL query document` 描述了 GraphQL服务端接收到的完整文件或请求字符串,一个 `document` 包含多重的 `Fragments`(查询片段) 和 `Operations`(操作) 定义。只有 `GraphQL query documents`包含 `operation` 时才能由服务端执行。然而,不包含操作的仍然可以被 解析 和 验证,以允许 客户端表示跨越多个 `document`的单个请求。
#### Operations(操作)
![](https://box.kancloud.cn/179e089b37fe0fa9feac14d8401d6c9b_641x172.jpg)
GraphQL 模型有两种`operations` 类型
* query - 只读获取
* mutation - 写 然后 获取
第一个`operation`通过可选的 操作名 和 选择集合表示。
例如,这个 `mutation operation` 要 点赞一个故事,然后检索新的点赞总数。
~~~
mutation {
likeStory(storyID: 12345) {
story {
likeCount
}
}
}
~~~
##### query 简写
如果 `document ` 只包含一个查询操作,并且这个查询定义不包含` varia![](https://box.kancloud.cn/5db41916f38e1a9d053c7a5c54cdb6b4_526x83.jpg)bles`(变量)同时也没有 `directives`(指令),那么这个操作可以表示成省略 查询关键字 和查询名字的简写形式。
下面是一个通过 `query` 简写的例子。
~~~
{
field
}
~~~
#### Selection Sets
![](https://box.kancloud.cn/9bc51c4c616001d9bc0b6d42213669a7_350x184.jpg)
操作选择所需的一组信息,它接收准确的信息,避免过度获取以及获取不足。
~~~
{
id
firstName
lastName
}
~~~
这个查询中,`id`,`firstName`,`lastName`字段构成选择集,选择集也可以包含 `fragment`引用。
#### Fields
![](https://box.kancloud.cn/5db41916f38e1a9d053c7a5c54cdb6b4_526x83.jpg)
`selecton set`主要由字段组成,一个字段描述在选择集内可以请求到的一个独立的信息。
有一些字段描述复杂的数据或关联其他的数据,为了近一步检索这些数据,字段自己可能包含一个`selecton set`,允许深层嵌套请求。所有GraphQL的操作都必须将其选择集最终指定到返回`scalar values`的字段,以保证明确的返回值。
下面的`operation`选择复杂数据的字段并且最终关联到 `scalar values`
~~~
{
me {
id
firstName
lastName
birthday {
month
day
}
friends {
name
}
}
}
~~~
在 `operation`的 `top-level` `selection set`中的字段常常 表示 应用程序及其` current viewer`(当前访问者)的全局访问的某些信息。 这些顶端的字段 一些典型的例子 如 包含对当前登录者的引用,或者访问由唯一标识引用的某些数据类型。
~~~
# `me` could represent the currently logged in viewer.
{
me {
name
}
}
# `user` represents one of many users in a graph of data, referred to by a
# unique identifier.
{
user(id: 4) {
name
}
}
~~~
#### arguments
![](https://box.kancloud.cn/f343621597492eb15e28c3bdeec4ebfb_371x137.jpg)
字段在概念上是返回值的的函数,偶尔需要接收改变它的行为的参数,这些参数通常直接映射到GraphQL 服务实现中的函数参数。
下面的例子中,我们想要查询一个特殊的 用户(通过ID数据请求)和人物简介的特殊尺寸的图片。
~~~
{
user(id: 4) {
id
name
profilePic(size: 100)
}
}
~~~
给定的字段可以有许多参数。
~~~
{
user(id: 4) {
id
name
profilePic(width: 100, height: 50)
}
}
~~~
**参数是无序的**
字段的提供可以是任何顺序,并且保持语法意义上一致。
#### field Alias
![](https://box.kancloud.cn/12a8a8c0d934d10997d1b13df417d781_275x85.jpg)
默认的,在响应 结果中的 字段名字会使用查询字段的名字,然而,你可以通过指定别名来定义不同的名字。
下面的例子中,我们获取两张不同尺寸的简介图片,并且保证结果对象不会 键名重复:
~~~
{
user(id: 4) {
id
name
smallPic: profilePic(size: 64)
bigPic: profilePic(size: 1024)
}
}
~~~
返回结果
~~~
{
user(id: 4) {
id
name
smallPic: profilePic(size: 64)
bigPic: profilePic(size: 1024)
}
}
Which returns the result:
{
"user": {
"id": 4,
"name": "Mark Zuckerberg",
"smallPic": "https://cdn.site.io/pic-4-64.jpg",
"bigPic": "https://cdn.site.io/pic-4-1024.jpg"
}
}
~~~
`top - level` 的 查询字段,同样可以给定别名。
~~~
{
zuck: user(id: 4) {
id
name
}
}
~~~
返回结果
~~~
{
"zuck": {
"id": 4,
"name": "Mark Zuckerberg"
}
}
~~~
#### Fragments
![](https://box.kancloud.cn/ddf0c479e1cf8f5a5377099d53ca9d7e_569x211.jpg)
片段是GraphQ中主要的组成单位。
`Fragments` 允许复用 普通的重复的选择字段,减少在 `document` 中的重复文本,当针对`interface`或`union`类型时,`Inline Fragments` 可以直接在选集中 用于特定类型。
例如,如果我们想获取一些关于共同朋友以及一些用户的朋友的共同信息。
~~~
query noFragments {
user(id: 4) {
friends(first: 10) {
id
name
profilePic(size: 50)
}
mutualFriends(first: 10) {
id
name
profilePic(size: 50)
}
}
}
~~~
重复的字段可以提取到一个`fragment`,并且通过查询或 parent`fragment`组合。
~~~
query withFragments {
user(id: 4) {
friends(first: 10) {
...friendFields
}
mutualFriends(first: 10) {
...friendFields
}
}
}
fragment friendFields on User {
id
name
profilePic(size: 50)
}
~~~
通过使用` spread operator `(…),通过`fragment`所有选择的字段会以与` fragment spreads`调用相同的层级被加入到 查询字段选集中。
例如:
~~~
query withNestedFragments {
user(id: 4) {
friends(first: 10) {
...friendFields
}
mutualFriends(first: 10) {
...friendFields
}
}
}
fragment friendFields on User {
id
name
...standardProfilePic
}
fragment standardProfilePic on User {
profilePic(size: 50)
}
~~~
##### Type Conditions
![](https://box.kancloud.cn/5a327ce69a20263ad01c00662ef7318c_339x77.jpg)
`Fragments`必须指定适用的`type`,上面的`friendFields`可用在查询`User`类型的上下文中。
`Fragments`不能指定为 `input value`(`scalar`,`enumeration`, or `input object`)。
`fragments`能够指定为`object types`, `interfaces`, and `unions`。
片段内的选集只有在当前操作的对象的具体类型匹配片段的类型时才返回值。
下面例子中 对facebook 数据模型的查询。
~~~
query FragmentTyping {
profiles(handles: ["zuck", "cocacola"]) {
handle
...userFragment
...pageFragment
}
}
fragment userFragment on User {
friends {
count
}
}
fragment pageFragment on Page {
likers {
count
}
}
~~~
`profiles` `root field`返回一个列表,列表的每个元素可能是`Page` 或`User`。当`profiles`的结果是`User`时,会出现`frields`字段而`likers`,反之当结果是`Page`则
`likers`会出现`friends`不会出现。
~~~
{
"profiles": [
{
"handle": "zuck",
"friends": { "count" : 1234 }
},
{
"handle": "cocacola",
"likers": { "count" : 90234512 }
}
]
}
~~~
##### Inline Fragments
![](https://box.kancloud.cn/c585c16a18a90bfc7c211dd02fc7b19a_474x79.jpg)
`Fragments`可以在选择集内内联定义,这是为了基于它运行时`type`有条件地包含字段。上面使用标准`fragment`包含的特性,使用`Inline fragments`同样能实现 。
~~~
query inlineFragmentTyping {
profiles(handles: ["zuck", "cocacola"]) {
handle
... on User {
friends {
count
}
}
... on Page {
likers {
count
}
}
}
}
~~~
`Inline fragments` 也可以用于将`directive`应用于一组字段。如果 忽略掉`TypeCondition`,` inline fragment`被认为与当前封闭上下文具有相同的`type`
~~~
query inlineFragmentNoType($expandedInfo: Boolean) {
user(handle: "zuck") {
id
name
... @include(if: $expandedInfo) {
firstName
lastName
birthday
}
}
}
~~~