《解析GraphQL 的查詢語法》【譯】

《解析GraphQL 的查詢語法》【譯】

原文鏈接: The Anatomy of a GraphQL Query
GraphQL 日漸成為數據查詢的主流標準之一,整個生態圈也蓬勃發展。本文則由淺入深地詳細介紹基礎的GraphQL 格式與關鍵字,有助於初學者對於GraphQL 的使用形成體系認知。

GraphQL日漸成為數據查詢的主流標準之一。每天都會產生許多圍繞這項技術發展的精彩討論和新工具。 GraphQL 最棒的特性就是提供了一個豐富語言集來描述獲取數據的API 。但是用戶該如何描述這種查詢語言,以及GraphQL 這項核心技術本身呢? let's talk !

GraphQL specification解釋了幾乎所有出現在GraphQL查詢語言中的概念,但是這篇文檔實在是太長了,所以我準備在這篇部落格中,借助一些具體的栗子來闡述其中一些最重要的概念,來幫助你成為GraphQL 專家!至少在紙上談兵方面: )

注!這篇文章可不是GraphQL 的入門讀物。首先,你應該通讀concepts on the graphql.org docs ,然後通過Learn Apollo tutorial來學習使用GraphQL ,最後當你想繼續深入了解這項技術時,再回到這裡來吧!

最基本的GraphQL查詢

大家通常會使用“查詢”來稱呼GraphQL API 服務的一切。但是這樣稱呼會有太多東西混雜在一起了。我們可能會把我們跪求服務端的一系列行為稱為一次查詢、一次修改或者一次訂閱,但我想“請求( request )”這個詞可能更加符合HTTP通信的概念,下面我們先來定義一些最基礎的概念:

  • GraphQL請求體:使用GraphQL語言定義的一個或多個操作或者數據片段,類型是字符串。
  • 操作:可以被GraphQL執行引擎理解的一次查詢、修改或訂閱。

為了搞清楚GraphQL 各種基本操作之間的區別,讓我們先來看一個簡單的GraphQL 請求體:

A simple query and its parts.

這個請求體顯示了GraphQL 的主要構建塊,它指定了你嘗試獲取的數據。

  • 字段( Fields ) :客戶端請求的數據單元,最後作為JSON響應數據中的一個字段。請注意,它們始終稱為“字段”,無論它們所在的層次有多深。在你的查詢中,對根節點字段的處理和最底層字段應該是一樣的。
  • 參數( Arguments ) :一組與特定字段關聯的鍵值對。這些參數會跟它們相關的字段一起被傳遞到服務器端執行,並影響服務器對字段的處理方式。如上面的範例,參數可以是字面量,接下來還有參數作為變量形式的栗子。請注意,參數可以顯示在任何字段中,即使是嵌套層次很深的字段。

為了讓你以非常簡潔的形式定義一個GraphQL 查詢,上面的栗子是GraphQL 的一種非常簡單的形式。但是在GraphQL 操作中三種可選的部分都沒有在上述栗子中使用。如果你不僅僅是用GraphQL 執行查詢操作,或是希望傳遞動態變量到GraphQL 查詢中,你就需要利用到這些新的GraphQL 特性。

這裡恰好有一個包含了所有可選部分的栗子:

A more detailed query and its parts.
  • 操作類型( Operation type ) :共三種類型:查詢( query )、更新( mutation )、訂閱( subscription )。它描述了你試圖進行何種操作。然而這些看起來意思很接近的操作,GraphQL 服務器處理它們時還是會有一些不同。
  • 操作名稱( Operation name ) :為了方便調試和服務端打日誌,最好給你的查詢賦予語義化的命名。這樣,無論你是在網絡日誌中或者GraphQL服務器上發現錯誤,你都可以通過名字很輕鬆的在代碼庫中定位問題,而不是靠猜測(類似的工具有Apollo Optics )。可以把操作名稱想像成你最喜歡的編程語言中,一個語義化的函數名。
  • 變量定義( Variable definitions ) :當客戶端向GraphQL服務器發送查詢時,會存在查詢文檔不變,當某些字段會動態變化的情況。這些就是查詢中的變量。因為GraphQL 是靜態類型的,它可以實時驗證你是否傳遞了正確的變量。這正是你聲明變量類型時所計劃提供的能力。

變量使用特定的序列化協議(在目前的GraphQL 服務實現中,通常是使用JSON )通過查詢文檔獨立傳輸。下面是一個變量對像在查詢文檔中的範例:

An example variables object.

可以看到,這裡的關鍵是變量名稱需要與變量定義所匹配,其名稱是Episode枚舉中的一個成員。

  • 變量( Variables ) :它是傳遞給GraphQL operation的值的字典,提供了operation的動態入參。

這裡有一個在談及GraphQL 的技術意義時很重要,卻不常被提及的核心概念——花括號之間的所有東西叫什麼?

選擇集( selection set )是一個會在GraphQL文檔中經常出現的概念,它賦予了GraphQL遞歸的特性,允許你獲取嵌套形式的數據。

  • 選擇集( selection set ) :它是一次operation中需要的一組字段,或者被嵌套在其他的字段中。 GraphQL查詢必須包含一個標識選擇集的字段,且該字段返回的是對像類型,選擇集不能設置在返回值是標量類型( Scalar Types )的字段上,例如Int或者String

片段( Fragments )

當開始介紹片段( fragments )之後,GraphQL 將變得更加強大。它帶來了一系列新的概念。

  • 片段定義( Fragment definition ) :定義一個片段是GraphQL文檔的一部分。為了區別於我們下面會介紹的內聯片段,它有時候也被稱為片段命名
A fragment definition and its parts.
  • 片段名稱( Fragment name ):片段( fragments )名在GraphQL文檔中必須是唯一的。這個名稱用於在操作( operations )或者其他片段( fragments )引用片段( fragments )。就像操作( operations )名稱一樣,片段名也能用於服務端日誌調試,所以我們推薦使用明確且有意義的片段( fragments )名。如果你使用了正確的片段( fragments )名,在優化數據獲取時,你能夠很好的追踪你的代碼。
  • 類型條件( Type condition ): GraphQL操作總是開始於查詢、修改或者訂閱schema中的類型,但是片段( fragments )能夠用於任一選擇,所以為了將校驗片段( fragments )與校驗schema獨立開,你需要指定片段( fragments )能夠使用的類型,而這就是類型條件( Type condition )的作用。

就像操作( operations )一樣,片段也選擇集,使用起來也跟在操作( operations )中使用選擇集一樣。

在你的操作( operations )中使用片段( fragments )

片段( fragments )只有在操作( operations )中使用才能發揮出作用。片段是GraphQL 的主要組合數據結構,通過片段可以重用重複的字段選擇,減少query 中的重複內容。接下來我們將介紹使用片段( fragments )的兩種方式:

  • 片段擴展運算符( Fragment spread ):當你在操作或者其他片段中使用片段時,你可以將片段名置於...之後來表示片段。例如沒有片段時需要這樣編寫query:
query noFragments { user(id: 4) { friends(first: 10) { id name profilePic(size: 50) } mutualFriends(first: 10) { id name profilePic(size: 50) } } }

query 中存在下列重複的選擇集合:

{ id name profilePic(size: 50) }

可以用片段簡化為:

query withFragments { user(id: 4) { friends(first: 10) { ...friendFields } mutualFriends(first: 10) { ...friendFields } } } fragment friendFields on User { id name profilePic(size: 50) }

使用片段時需要加上...操作符表示展開片段內容,這稱為片段擴展運算符( fragment spread ),它可以用在任何選擇集( selection set )中,用以匹配片段的類型條件。

  • 內聯片段( Inline fragment ):如果你僅僅是想執行一些依賴結果類型的字段,卻不想把它們抽離成獨立的定義,你可以使用內聯片段( inline fragment ) 。它使用起來跟獨立的命名片段一樣,但是寫在查詢的內部。有一點不同的是,對於內聯片段來說類型條件( type condition )不是必須的,可以像使用指令一樣來使用它,接下來我們會演示指令( directive )的栗子。

指令( Directives )

指令是獨立於GraphQL server 之外的一個附加功能。指令不會對結果的值產生影響,但是會影響哪些結果會被返回,也許還會影響這些結果是如何被執行的。指令可以出現在查詢的任何地方,但在這篇文章中我們只關注當前GrahpQL文檔所描述的skip(忽略)include(包括)兩個指令。

You probably wouldn't usually put all of these in one query, but it's the easiest way to demonstrate.

你能在上文廚房水槽的栗子中使用指令skipincludeinclude指令表示只有在if參數為true時才引入片段表示的字段。 skip指令表示在if參數為true時忽略片段中的字段。由於指令的語法相當靈活,我們可以利用它來給GraphQL 添加更多的特性,而不是使用語法解析或者引入更複雜的工具的方式。

  • 指令( Directive ):在字段、片段或者查詢中的一個註釋, include指令表示只有在if參數為true時才引入片段表示的字段。 skip指令表示在if參數為true時忽略片段中的字段。
  • 指令參數( Directive arguments ):與字段參數類似,只不過它們是被執行引擎處理,而不是傳遞給字段解析器( field resolver )。

總結

GraphQL 是在應用層對業務數據模型的抽象,是對數據請求定制的DSQL,它解除了接口和數據之間的綁定,對業務數據結構做了抽象和整理,業務邏輯中的數據依賴於底層數據庫結構,並且可以由具體業務場景來定制,不同的業務場景只要基於同樣一套基礎業務數據模型就可以得到復用,在我看來,這才是GraphQL 帶來的最大改變和收益。目前GitHub整站API已遷移GraphQL ,淘寶也在生產環境有所實踐。

參考文檔:

福利時間

騰訊LIVE開發者大會

由騰訊IVWEB 團隊匠心打造的TLC 大會(騰訊音視頻開發者大會)再度來襲,距離5折早鳥票搶購僅剩2天,手慢無哦!

本次TLC 大會主題涵蓋AI 人體姿態識別、NBA 直播系統千萬高並發架構、世界杯直播技術揭秘、春節期間最熱門的在線答題方案剖析,更有當下最熱門的移動端Google Flutter 、RN 和小程序在直播中的實踐場景,本次大會,我們邀請了國內外16名直播行業專家,他們來自Instagram、騰訊、YY、聲網、熊貓直播、陌陌、即構科技等國內外知名直播/視頻領域企業,這將是一場視頻領域的嘉年華。

大會官網:

購票地址:

感興趣的同學,可以加筆者的微信:zhulin-09,領取優惠碼: )

確認購票成功的用戶,我會拉進TLC 用戶群,跟大會講師和BAT 技術大牛一起交流技術哦~

What do you think?

Written by marketer

如何監控網頁崩潰?

Facebook工程師CatChen 確認出席FEDAY