GraphQL 類型 - AWS AppSync

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

GraphQL 類型

GraphQL 支援許多不同類型的 。如上一節所示,類型會定義資料的形狀或行為。它們是 GraphQL 結構描述的基本建置區塊。

類型可以分類為輸入和輸出。輸入是允許作為特殊物件類型 (Query、 等) 的引數傳入的類型Mutation,而輸出類型會嚴格用於儲存和傳回資料。類型及其分類的清單如下:

  • 物件 :物件包含描述實體的欄位。例如,物件可以是類似 的物件,book其中包含描述其特徵的欄位publishingYear,例如 authorName、 等。它們是嚴格輸出類型。

  • Scalars :這些是基本類型,例如 int、 string 等。它們通常會指派給 欄位。使用 authorName 欄位作為範例,可以指派String純量來存放名稱,例如 "John Smith"。Scalars 可以是輸入和輸出類型。

  • 輸入 :輸入可讓您傳遞一組欄位作為引數。它們的結構與物件非常相似,但可以作為引數傳遞給特殊物件。輸入可讓您定義其範圍內的純量、列舉和其他輸入。輸入只能是輸入類型。

  • 特殊物件 :特殊物件會執行狀態變更操作,並大量提升服務。有三種特殊物件類型:查詢、突變和訂閱。查詢通常會擷取資料;突變會處理資料;訂閱會開啟並維護用戶端與伺服器之間的雙向連線,以進行持續通訊。特殊物件的功能不是輸入或輸出。

  • 列舉 :列舉是預先定義的法律值清單。如果您呼叫列舉,其值只能是其範圍中定義的值。例如,如果您有一個名為 的列舉,trafficLights描述流量訊號清單,則其可能具有 redLight和 等值,greenLight但不會有 等值purpleLight。真正的流量指示燈只會有這麼多的訊號,因此您可以使用列舉來定義它們,並在參考 時強制它們成為唯一的法律值trafficLight。列舉可以是輸入和輸出類型。

  • Unions/interfaces :Unions 可讓您根據用戶端請求的資料,在請求中傳回一或多個物件。例如,如果您的 Book類型具有 title 欄位,而 Author類型具有 name 欄位,則可以在這兩種類型之間建立 工會。如果您的用戶端想要查詢「Julius Caesar」一詞的資料庫,則工會可以從 傳回 Julius Caesar (William Shakespeare 的播放),Booktitle並從 傳回 Julius Caesar AuthorCommentsarii de Bello Gallico 的作者)name。聯合只能是輸出類型。

    介面是物件必須實作的一組欄位。這與 Java 等程式設計語言的介面有點類似,您必須在其中實作介面中定義的欄位。例如,假設您建立了名為 的介面Book,其中包含 title 欄位。假設您稍後建立了名為 的類型Novel,該類型已實作 Book。您的 Novel必須包含 title 欄位。不過,您的 Novel 也可以包含不在 介面中的其他欄位,例如 pageCountISBN。介面只能是輸出類型。

下列各節將說明每種類型如何在 GraphQL 中運作。

物件

GraphQL 物件是您將在生產程式碼中看到的主要類型。在 GraphQL 中,您可以將物件視為不同欄位的群組 (類似其他語言的變數),每個欄位都由可保留值的類型 (通常是純量或其他物件) 定義。物件表示可從您的服務實作擷取/操作的資料單位。

物件類型是使用 Type 關鍵字宣告。讓我們稍微修改結構描述範例:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String }

此處的物件類型為 PersonOccupation。每個物件都有自己的欄位和自己的類型。GraphQL 的一項功能是能夠將欄位設定為其他類型。您可以看到 中的 occupation 欄位Person包含Occupation物件類型。我們可以建立此關聯,因為 GraphQL 只會描述資料,而不是服務的實作。

純量

Scalars 基本上是保留值的原始類型。在 中 AWS AppSync,純量有兩種類型:預設 GraphQL 純量和 AWS AppSync 純量。Scalars 通常用於在物件類型中存放欄位值。預設 GraphQL 類型包括 IntFloatBooleanStringID。讓我們再次使用上一個範例:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String }

探查 nametitle 欄位,兩者都保留純量。 String Name可能會傳回 "John Smith" 之類的字串值,而標題可能會傳回 "firefighter" 之類的字串值。某些 GraphQL 實作也支援使用 Scalar關鍵字和實作類型行為的自訂純量。不過, AWS AppSync 目前不支援自訂純量。如需純量清單,請參閱 中的純量類型 AWS AppSync

輸入

由於輸入和輸出類型的概念,傳遞引數時存在某些限制。通常需要傳入的類型會受到限制,特別是物件。您可以使用輸入類型略過此規則。輸入是包含純量、列舉和其他輸入類型的類型。

輸入是使用input關鍵字定義:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } input personInput { id: ID! name: String age: Int occupation: occupationInput } input occupationInput { title: String }

如您所見,我們可以有模擬原始類型的個別輸入。這些輸入通常會用於您的欄位操作,如下所示:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } input occupationInput { title: String } type Mutation { addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person }

請注意,我們仍以 occupationInput 取代 Occupation 來建立 Person

這只是輸入的一個案例。它們不一定需要 1:1 複製物件,而在生產程式碼中,您很可能不會像這樣使用物件。最好只定義輸入為引數所需的內容,藉此利用 GraphQL 結構描述。

此外,相同的輸入可用於多個操作,但我們不建議這樣做。每個操作理想情況下都應包含自己的唯一輸入複本,以防結構描述的要求變更。

特殊物件

GraphQL 會為特殊物件保留一些關鍵字,這些物件會針對結構描述擷取/處理資料的方式定義部分業務邏輯。在結構描述中,最多可以有其中一個關鍵字。它們可作為用戶端針對 GraphQL 服務執行的所有請求資料的進入點。

特殊物件也會使用 type 關鍵字定義。雖然它們的使用方式與一般物件類型不同,但其實作非常類似。

Queries

查詢與 GET 的操作非常類似,因為它們執行唯讀擷取,以從您的來源取得資料。在 GraphQL 中, 會Query定義針對伺服器提出請求之用戶端的所有進入點。您的 GraphQL 實作Query中一律會有 。

以下是我們在先前結構描述範例中使用的 Query和 修改過的物件類型:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } type Query { people: [Person] }

我們的 Query包含一個名為 的欄位people,從資料來源傳回Person執行個體清單。假設我們需要變更應用程式的行為,現在我們需要針對某些不同的目的,僅傳回Occupation執行個體的清單。我們可以將其新增至查詢:

type Query { people: [Person] occupations: [Occupation] }

在 GraphQL 中,我們可以將查詢視為請求的單一來源。如您所見,這可能比使用不同端點來實現相同物件的RESTful實作更簡單 (.../api/1/people.../api/1/occupations)。

假設我們有此查詢的解析程式實作,我們現在可以執行實際查詢。當類型存在時,我們必須明確呼叫該Query類型,才能在應用程式的程式碼中執行。這可以使用query關鍵字來完成:

query getItems { people { name } occupations { title } }

如您所見,此查詢稱為 getItems並傳回 peoplePerson物件清單) 和 occupationsOccupation物件清單)。在 中people,我們只會傳回每個 name的欄位Person,同時會傳回每個 title的欄位Occupation。回應可能如下所示:

{ "data": { "people": [ { "name": "John Smith" }, { "name": "Andrew Miller" }, . . . ], "occupations": [ { "title": "Firefighter" }, { "title": "Bookkeeper" }, . . . ] } }

範例回應顯示資料如何遵循查詢的形狀。擷取的每個項目都會列在 欄位的範圍內。 occupations people會傳回個別清單的項目。雖然有用,但修改查詢以傳回人員名稱和職業清單可能更方便:

query getItems { people { name occupation { title } }

這是合法修改,因為我們的Person類型包含 類型的occupation欄位Occupation。在 範圍內列出時people,我們會傳回每個 Person的 ,name以及其Occupation與 相關聯的 title。回應可能如下所示:

} "data": { "people": [ { "name": "John Smith", "occupation": { "title": "Firefighter" } }, { "name": "Andrew Miller", "occupation": { "title": "Bookkeeper" } }, . . . ] } }
Mutations

突變類似於 PUT或 等狀態變更操作POST。他們執行寫入操作來修改來源中的資料,然後擷取回應。它們會定義資料修改請求的進入點。與查詢不同,根據專案的需求,突變可能會也可能不會包含在結構描述中。以下是結構描述範例中的突變:

type Mutation { addPerson(id: ID!, name: String, age: Int): Person }

addPerson 欄位代表一個Person將 新增至資料來源的輸入點。 addPerson是欄位名稱;idnameage是參數; Person 是傳回類型。回顧Person類型:

type Person { id: ID! name: String age: Int occupation: Occupation }

我們已新增 occupation 欄位。不過,我們無法將此欄位Occupation直接設定為 ,因為物件無法以引數形式傳入;它們是嚴格輸出類型。我們應該傳遞具有與引數相同欄位的輸入:

input occupationInput { title: String }

我們也可以輕鬆更新我們的 addPerson ,在建立新的Person執行個體時將此項目納入為 參數:

type Mutation { addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person }

以下是更新的結構描述:

type Person { id: ID! name: String age: Int occupation: Occupation } type Occupation { title: String } input occupationInput { title: String } type Mutation { addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person }

請注意, occupation將從 傳入 title 欄位occupationInput,以完成 的建立,Person而不是原始Occupation物件。假設我們有適用於 的解析程式實作addPerson,我們現在可以執行實際的突變。當類型存在時,我們必須明確呼叫該Mutation類型,才能在應用程式的程式碼中執行。這可以使用mutation關鍵字來完成:

mutation createPerson { addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) { name age occupation { title } } }

此突變稱為 createPersonaddPerson是 操作。若要建立新的 Person,我們可以輸入 id、、 nameage和 的引數occupation。在 的範圍內addPerson,我們也可以看到其他欄位name,例如 age、 等。這是您的回應;這些欄位會在addPerson操作完成後傳回。以下是範例的最後一部分:

mutation createPerson { addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") { id name age occupation { title } } }

使用此突變時,結果可能如下所示:

{ "data": { "addPerson": { "id": "1", "name": "Steve Powers", "age": "50", "occupation": { "title": "Miner" } } } }

如您所見,回應會傳回我們請求的值,其格式與在突變中定義的相同。最好傳回所有已修改的值,以減少混淆,以及未來需要更多查詢。突變可讓您在其範圍內包含多個操作。它們將依突變中列出的順序依序執行。例如,如果我們建立另一個名為 的操作addOccupation,將任務標題新增至資料來源,則在 之後,我們可以在 突變中呼叫此 addPersonaddPerson會先處理,再處理 addOccupation

Subscriptions

訂閱用於在伺服器及其用戶端之間WebSockets開啟持久的雙向連線。一般而言,用戶端會訂閱或接聽伺服器。每當伺服器進行伺服器端變更或執行事件時,訂閱的用戶端都會收到更新。當訂閱多個用戶端且需要通知伺服器或其他用戶端中發生變更時,此類型的通訊協定非常有用。例如,訂閱可用來更新社交媒體摘要。可能會有兩個使用者,即使用者 A 和使用者 B,這些使用者在接收直接訊息時都會訂閱自動通知更新。用戶端 A 上的使用者 A 可以傳送直接訊息給用戶端 B 上的使用者 B。使用者 A 的用戶端會傳送直接訊息,該訊息將由伺服器處理。然後,伺服器會在傳送自動通知至用戶端 B 時,將直接訊息傳送至使用者 B 的帳戶。

以下是Subscription我們可以新增至結構描述範例的範例:

type Subscription { personAdded: Person }

每當有新的 新增至資料來源Person時, personAdded 欄位都會傳送訊息給訂閱的用戶端。假設我們有適用於 的解析程式實作personAdded,我們現在可以使用訂閱。當類型存在時,我們必須明確呼叫該Subscription類型,才能在應用程式的程式碼中執行。這可以使用subscription關鍵字來完成:

subscription personAddedOperation { personAdded { id name } }

訂閱稱為 personAddedOperation,操作為 personAddedpersonAdded會傳回新Person執行個體的 idname 欄位。查看突變範例,我們使用Person此操作新增 :

addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")

如果我們的客戶訂閱了新新增 的更新Person,則addPerson執行後可能會看到:

{ "data": { "personAdded": { "id": "1", "name": "Steve Powers" } } }

以下是訂閱提供的摘要:

訂閱是雙向管道,可讓用戶端和伺服器快速但穩定地接收更新。他們通常會使用 WebSocket 通訊協定,這會建立標準化且安全的連線。

訂閱具有靈活性,因為它們可減少連線設定開銷。訂閱後,用戶端可以長時間繼續在該訂閱上執行。他們通常會允許開發人員自訂訂閱的生命週期,並設定需要的資訊,藉此有效率地使用運算資源。

一般而言,訂閱可讓用戶端一次進行多個訂閱。由於訂閱與 相關 AWS AppSync,因此訂閱僅用於接收服務的即時更新 AWS AppSync 。它們不能用於執行查詢或突變。

訂閱的主要替代方案是輪詢,它會以設定的間隔傳送查詢以請求資料。此程序通常比訂閱效率低,並對用戶端和後端造成很大壓力。

我們的結構描述範例中未提到的一件事,就是您的特殊物件類型也必須在schema根中定義。因此,當您在 中匯出結構描述時 AWS AppSync,看起來可能會像這樣:

schema.graphql
schema { query: Query mutation: Mutation subscription: Subscription } . . . type Query { # code goes here } type Mutation { # code goes here } type Subscription { # code goes here }

列舉

列舉或列舉是限制類型或欄位可能具有之法律引數的特殊純量。這表示每當列舉在結構描述中定義時,其關聯的類型或欄位將限制為列舉中的值。列舉會序列化為字串純量。請注意,不同的程式設計語言可能會以不同的方式處理 GraphQL 列舉。例如, JavaScript 沒有原生列舉支援,因此列舉值可以改為映射至整數值。

列舉是使用 enum關鍵字定義。範例如下:

enum trafficSignals { solidRed solidYellow solidGreen greenArrowLeft ... }

呼叫trafficLights列舉時,引數只能是 solidRedsolidYellowsolidGreen等 (enum)。使用列舉來描述具有不同但有限選擇數量的物件是常見的。

連線/介面

請參閱 GraphQL 中的介面和聯合