[TOC]
#### 語法

#### 定義
`GraphQL query document` 描述了 GraphQL服務端接收到的完整文件或請求字符串,一個 `document` 包含多重的 `Fragments`(查詢片段) 和 `Operations`(操作) 定義。只有 `GraphQL query documents`包含 `operation` 時才能由服務端執行。然而,不包含操作的仍然可以被 解析 和 驗證,以允許 客戶端表示跨越多個 `document`的單個請求。
#### Operations(操作)

GraphQL 模型有兩種`operations` 類型
* query - 只讀獲取
* mutation - 寫 然后 獲取
第一個`operation`通過可選的 操作名 和 選擇集合表示。
例如,這個 `mutation operation` 要 點贊一個故事,然后檢索新的點贊總數。
~~~
mutation {
likeStory(storyID: 12345) {
story {
likeCount
}
}
}
~~~
##### query 簡寫
如果 `document ` 只包含一個查詢操作,并且這個查詢定義不包含` variables`(變量)同時也沒有 `directives`(指令),那么這個操作可以表示成省略 查詢關鍵字 和查詢名字的簡寫形式。
下面是一個通過 `query` 簡寫的例子。
~~~
{
field
}
~~~
#### Selection Sets

操作選擇所需的一組信息,它接收準確的信息,避免過度獲取以及獲取不足。
~~~
{
id
firstName
lastName
}
~~~
這個查詢中,`id`,`firstName`,`lastName`字段構成選擇集,選擇集也可以包含 `fragment`引用。
#### Fields

`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

字段在概念上是返回值的的函數,偶爾需要接收改變它的行為的參數,這些參數通常直接映射到GraphQL 服務實現中的函數參數。
下面的例子中,我們想要查詢一個特殊的 用戶(通過ID數據請求)和人物簡介的特殊尺寸的圖片。
~~~
{
user(id: 4) {
id
name
profilePic(size: 100)
}
}
~~~
給定的字段可以有許多參數。
~~~
{
user(id: 4) {
id
name
profilePic(width: 100, height: 50)
}
}
~~~
**參數是無序的**
字段的提供可以是任何順序,并且保持語法意義上一致。
#### field Alias

默認的,在響應 結果中的 字段名字會使用查詢字段的名字,然而,你可以通過指定別名來定義不同的名字。
下面的例子中,我們獲取兩張不同尺寸的簡介圖片,并且保證結果對象不會 鍵名重復:
~~~
{
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

片段是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

`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

`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
}
}
}
~~~