簡介
- GraphQL是一個用于API的查詢語言,一個使用基于類型系統來執行查詢的服務端運行時
- GraphQL未與任何特定數據庫,存儲引擎綁定,而是依靠現有代碼和數據支撐
查詢和變更
字段(Fields)
- GraphQL關于請求對象上的特定字段
- 查詢和查詢的結果擁有一致的數據結構(很重要)
- 客戶端得到想要的數據
- 服務器準確知道客戶端請求的字段
- 可以對對象字段進行次級選擇
// 查詢
{
hero {
name
# 可以添加備注
friends {
name
}
}
}
// 結果
{
"data" : {
"hero": {
"name": "wxy",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
參數(Arguments)
- 每一個字段,嵌套對象都能有自己的一組參數,使得GraphQL可以完美替代多次API獲取請求
- 可以給標量(scalar)字段傳遞參數,GraphQL自帶一套默認類型,也可以自己定制類型,來序列化輸出格式
Schema和類型
// 查詢
{
human(id: "1000") {
name
height
}
}
// 結果
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
別名(Aliases)
- 通過別名,查詢相同字段的不同內容
// 查詢不同的hero
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
// 通過別名,查詢不同的hero
{
"data": {
"empireHero": {
"name": "Luke Skywalker"
},
"jediHero": {
"name": "R2-D2"
}
}
}
片段(Fragments)
- GraphQL可復用單元,好的抽象,可以避免重復代碼
{
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"
}
]
}
}
操作
一個操作query HeroNameAndFriends
- 操作類型關鍵字——描述打算做什么類型的操作
- query
- mutation
- subscription
- 操作名稱
HeroNameAndFriends
- 想象成函數名,有利于追蹤和調試
變量(Variables)
- 查詢參數可能是動態的,GraphQL擁有一級方法將動態值提取到查詢之外,然后作為分離的字典穿進去。這些動態值,就是變量
- 如何使用變量
- 使用
$variableName
替代查詢中的靜態值 - 聲明
$variableName
為查詢接收的變量之一 - 將
variableName: value
通過傳輸轉用(通常是JSON)的分離的變量字典中。
- 使用
- 用法
// 聲明
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
- 所有聲明的變量都必須是:
- 標量
- 枚舉值
- 輸入對象類型(與服務器有關)
- 要傳遞一個復雜對象到一個字段上,必須知道服務器上匹配的類型。
- 變量定義允許:
- 可選的
- 必要的,在類型后加
!
變量默認值
query HeroNameAndFriends($episode: Episode = "JEDI") {
hero(episode: $episode) {
name
friends {
name
}
}
}
指令(Directives)
- 指令可以附著在字段或者片段包含的字段上,以服務單期待的方式改變查詢的執行。
- GraphQL核心規范的兩個指令:
-
@include(if: Boolean)
僅在參數為true
,包含被指令附著的字段 -
@skip(if: Boolean)
如果參數為true
,跳過被指令附著的字段
-
變更(Mutations)
- 用來變更服務器數據的方法
- 建議導致寫入的操作都應該顯式的通過變更(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)
- GraphQL schema 具備自定義接口和聯合類型的能力
- 若查詢的字段返回的是接口/聯合類型,就需要內聯片段來去處下層具體類型的數據
//聲明
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)
- GraphQL允許在查詢的任何位置請求
__typename
,一個元字段,以獲得那個位置的對象
// 聲明
{
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"
}
]
}