GraphQL LogoGraphQL

查詢和變異

在這個頁面中,您將詳細瞭解如何查詢 GraphQL 伺服器。

欄位#

最簡單來說,GraphQL 就是要求物件中的特定欄位。讓我們從一個非常簡單的查詢開始,以及執行查詢時得到的結果

您可以立即看到查詢與結果的形狀完全相同。這對 GraphQL 來說至關重要,因為您永遠會得到預期的結果,而且伺服器確切知道客戶端要求的欄位。

欄位 name 傳回 String 類型,在本例中是星際大戰主要英雄的名稱,"R2-D2"

喔,還有一件事 - 上面的查詢是互動式的。這表示您可以隨意變更查詢,並查看新的結果。嘗試在查詢中的 hero 物件中新增一個 appearsIn 欄位,並查看新的結果。

在先前的範例中,我們只要求英雄的名稱,它傳回一個字串,但欄位也可以參照物件。在這種情況下,您可以為該物件進行欄位的子選取。GraphQL 查詢可以遍歷相關物件及其欄位,讓客戶端在一個要求中擷取大量相關資料,而不是像在傳統 REST 架構中需要進行多次往返。

請注意,在此範例中,friends 欄位傳回一個項目陣列。GraphQL 查詢對於單一項目或項目清單看起來都一樣;不過,我們可以根據架構中指示的內容知道要預期哪一個。

引數#

如果我們能做的只有遍歷物件及其欄位,GraphQL 對於資料擷取來說已經是非常有用的語言了。但當你加上傳遞引數給欄位的這個能力時,事情就變得更有趣了。

在像 REST 這樣的系統中,你只能傳遞一組引數,也就是你的要求中的查詢參數和 URL 區段。但在 GraphQL 中,每個欄位和巢狀物件都可以取得它自己的引數組,讓 GraphQL 成為執行多重 API 擷取的完整替代方案。你甚至可以傳遞引數到純量欄位,在伺服器上一次實作資料轉換,而不是在每個客戶端個別執行。

引數可以是許多不同的類型。在上述範例中,我們使用了列舉類型,它代表一組有限選項中的一個(在本例中,長度單位,可能是 METERFOOT)。GraphQL 附帶一組預設類型,但 GraphQL 伺服器也可以宣告它自己的自訂類型,只要它們可以序列化成你的傳輸格式即可。

在此處閱讀更多關於 GraphQL 類型系統的資訊。

別名#

如果你很敏銳,你可能會注意到,由於結果物件欄位與查詢中的欄位名稱相符,但沒有包含引數,因此你無法直接使用不同的引數查詢同一個欄位。這就是你需要別名的原因,它們讓你將欄位的結果重新命名成你想要的任何名稱。

在上述範例中,兩個 hero 欄位會產生衝突,但由於我們可以將它們別名成不同的名稱,因此我們可以在一個要求中取得兩個結果。

片段#

假設我們的應用程式中有一個相對複雜的頁面,讓我們可以並排檢視兩個英雄,以及他們的朋友。你可以想像這樣的查詢可能會很快變得複雜,因為我們需要重複這些欄位至少一次,也就是比較中的每一邊。

這就是 GraphQL 包含稱為片段的可重複使用單元的原因。片段讓你建構欄位集合,然後在需要時將它們包含在查詢中。以下是你可以使用片段解決上述情況的範例

你可以看到如果重複欄位,上述查詢會非常重複。片段的概念經常被用來將複雜的應用程式資料需求拆分為較小的區塊,特別是當你需要將許多 UI 元件與不同的片段組合成一個初始資料擷取時。

在片段中使用變數#

片段可以存取在查詢或突變中宣告的變數。請參閱變數

作業名稱#

在上述的幾個範例中,我們使用簡寫語法,省略了 query 關鍵字和查詢名稱,但在實際應用程式中,使用這些會讓我們的程式碼較不含糊。

以下是一個範例,其中包含關鍵字 query 作為作業類型,以及 HeroNameAndFriends 作為作業名稱

作業類型可能是查詢突變訂閱,並描述你打算執行的作業類型。作業類型是必需的,除非你使用查詢簡寫語法,在這種情況下,你無法為你的作業提供名稱或變數定義。

操作名稱 是操作的有意義且明確的名稱。它僅在多操作文件中有需要,但建議使用,因為它對除錯和伺服器端記錄非常有幫助。當發生問題時(您在網路記錄或 GraphQL 伺服器的記錄中看到錯誤),透過名稱識別程式碼庫中的查詢比嘗試解讀內容更容易。就像您最喜歡的程式語言中的函式名稱一樣。例如,在 JavaScript 中,我們可以輕鬆地只使用匿名函式,但當我們為函式命名時,就更容易追蹤、除錯程式碼,並在呼叫時記錄。同樣地,GraphQL 查詢和突變名稱,以及片段名稱,可以成為伺服器端識別不同 GraphQL 請求的有用除錯工具。

變數#

到目前為止,我們一直在查詢字串中撰寫所有參數。但在大多數應用程式中,欄位的參數會是動態的:例如,可能有一個下拉式選單讓您選擇您有興趣的星際大戰集數,或一個搜尋欄位,或一組篩選器。

將這些動態參數直接傳遞到查詢字串中並非好主意,因為我們的用戶端程式碼需要在執行時動態處理查詢字串,並將其序列化為 GraphQL 特定的格式。相反地,GraphQL 有一種一流的方法可以將動態值從查詢中取出,並將它們作為一個單獨的字典傳遞。這些值稱為變數

當我們開始使用變數時,我們需要做三件事

  1. $variableName 取代查詢中的靜態值
  2. 宣告 $variableName 為查詢接受的變數之一
  3. 在獨立的、傳輸特定(通常為 JSON)變數字典中傳遞 variableName: value

以下為整體範例

現在,在我們的客戶端程式碼中,我們可以簡單地傳遞不同的變數,而不必建構全新的查詢。這通常也是標示查詢中哪些引數預期為動態的良好做法 - 我們絕不應該執行字串內插來建構使用者提供的值的查詢。

變數定義#

變數定義是上述查詢中看起來像 ($episode: Episode) 的部分。它就像型別語言中函式的引數定義一樣運作。它列出所有變數,其前綴為 $,後接其型別,在本例中為 Episode

所有宣告的變數都必須為純量、列舉或輸入物件型別。因此,如果您想將複雜物件傳遞到欄位中,您需要知道伺服器上符合哪個輸入型別。在 Schema 頁面上進一步了解輸入物件型別。

變數定義可以是選用的或必要的。在上述情況中,由於 Episode 型別旁邊沒有 !,因此它是選用的。但是,如果您要將變數傳遞到的欄位需要非 null 引數,則變數也必須為必要。

若要進一步了解這些變數定義的語法,學習 GraphQL schema 語言會很有用。Schema 語言在 Schema 頁面上有詳細說明。

預設變數#

也可以透過在型別宣告後新增預設值,將預設值指定給查詢中的變數。

query HeroNameAndFriends($episode: Episode = JEDI) {
hero(episode: $episode) {
name
friends {
name
}
}
}

當所有變數提供預設值時,您可以在不傳遞任何變數的情況下呼叫查詢。如果任何變數作為變數字典的一部分傳遞,它們將覆寫預設值。

指令#

我們在上面討論了變數如何使我們避免執行手動字串內插以建構動態查詢。在引數中傳遞變數解決了這些問題中相當大的一類,但我們可能還需要一種方法來使用變數動態更改查詢的結構和形狀。例如,我們可以想像一個具有摘要和詳細檢視的 UI 元件,其中一個包含比另一個更多的欄位。

讓我們為這樣的元件建構一個查詢

嘗試編輯上面的變數,改為傳遞 truewithFriends,並觀察結果如何變更。

我們需要使用 GraphQL 中稱為指令的新功能。指令可以附加到欄位或片段包含,並且可以以伺服器希望的任何方式影響查詢的執行。核心 GraphQL 規範包含兩個指令,任何符合規範的 GraphQL 伺服器實作都必須支援

  • @include(if: Boolean) 僅在引數為 true 的情況下將此欄位包含在結果中。
  • @skip(if: Boolean) 如果引數為 true,則略過此欄位。

指令對於擺脫需要執行字串處理以在查詢中新增和移除欄位的狀況很有用。伺服器實作也可以透過定義完全新的指令來新增實驗性功能。

突變#

大多數關於 GraphQL 的討論都集中在資料擷取上,但任何完整的資料平台都需要一種方法來修改伺服器端資料。

在 REST 中,任何請求都可能對伺服器造成一些副作用,但依慣例建議不要使用 GET 請求來修改資料。GraphQL 類似,技術上任何查詢都可以實作為資料寫入。然而,建立一個慣例很有用,任何造成寫入的運算都應該透過突變明確傳送。

就像在查詢中,如果突變欄位傳回一個物件類型,你可以要求巢狀欄位。這對於在更新後擷取物件的新狀態很有用。我們來看一個簡單的突變範例

請注意 createReview 欄位如何傳回新建立的評論的 starscommentary 欄位。這在突變現有資料時特別有用,例如,在遞增欄位時,因為我們可以用一個請求突變和查詢欄位的新值。

你可能也注意到,在此範例中,我們傳入的 review 變數不是一個純量。它是一個輸入物件類型,一種可以作為引數傳入的特殊物件類型。在 Schema 頁面進一步瞭解輸入類型。

突變中的多個欄位#

突變可以包含多個欄位,就像查詢一樣。除了名稱之外,查詢和突變之間有一個重要的區別

查詢欄位是並行執行的,而突變欄位是依序執行的,一個接一個。

這表示如果我們在一個請求中傳送兩個 incrementCredits 突變,第一個保證在第二個開始之前完成,確保我們不會與自己陷入競爭條件。

內嵌片段#

與許多其他類型系統一樣,GraphQL schema 包含定義介面和聯合類型的功能。在 schema 指南中瞭解它們。

如果您查詢傳回介面或聯集類型的欄位,您需要使用內嵌片段來存取底層具體類型的資料。使用範例最容易了解

在此查詢中,hero 欄位傳回 Character 類型,這可能是 HumanDroid,視 episode 參數而定。在直接選取中,您只能要求存在於 Character 介面中的欄位,例如 name

若要要求具體類型中的欄位,您需要使用具有類型條件的內嵌片段。由於第一個片段標示為 ... on Droid,因此只有當從 hero 傳回的 CharacterDroid 類型時,才會執行 primaryFunction 欄位。Human 類型的 height 欄位也類似。

命名片段也可以用相同的方式使用,因為命名片段總是附有類型。

元資料欄位#

由於在某些情況下您不知道會從 GraphQL 服務收到什麼類型,因此您需要一些方法來決定如何在用戶端處理該資料。GraphQL 允許您在查詢中的任何一點請求 __typename,這是一個元資料欄位,以取得該點的物件類型名稱。

在上述查詢中,search 傳回聯集類型,可以是三個選項之一。沒有 __typename 欄位,用戶端將無法區分不同的類型。

GraphQL 服務提供幾個元資料欄位,其餘欄位用於公開內省系統。

繼續閱讀 →架構和類型