本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
GraphQL 類型
GraphQL 支援許多不同的類型。如上一節所示,類型會定義資料的形狀或行為。它們是 GraphQL 結構描述的基本建置區塊。
類型可以分類為輸入和輸出。輸入是允許做為特殊物件類型 (Query、 等) 的引數傳入的類型Mutation,而輸出類型會嚴格用於存放和傳回資料。類型及其分類的清單如下所示:
-
物件:物件包含描述實體的欄位。例如,物件可以是類似 的物件,book其中包含描述其特性的欄位publishingYear,例如 authorName、 等。它們是嚴格輸出類型。
-
純量:這些是基本類型,例如 int、string 等。它們通常會指派給欄位。使用 authorName 欄位做為範例,可以指派String純量來存放名稱,例如 "John Smith"。純量可以是輸入和輸出類型。
-
輸入:輸入可讓您將一組欄位做為引數傳遞。它們的結構與物件非常類似,但可以做為引數傳遞給特殊物件。輸入可讓您在其範圍內定義純量、列舉和其他輸入。輸入只能是輸入類型。
-
特殊物件:特殊物件會執行變更狀態的操作,並執行大量繁重的服務。有三種特殊物件類型:查詢、變動和訂閱。查詢通常會擷取資料;變動會操作資料;訂閱會開啟和維護用戶端和伺服器之間的雙向連線,以進行持續通訊。特殊物件的功能不是輸入或輸出。
-
列舉:列舉是預先定義的法律值清單。如果您呼叫列舉,其值只能是其範圍中定義的值。例如,如果您有一個名為 的列舉,trafficLights描述流量訊號清單,它可能具有 redLight和 等值,greenLight但不會有 等值purpleLight。真正的交通燈只會有這麼多訊號,因此您可以使用列舉來定義它們,並在參考 時強制它們成為唯一的法律值trafficLight。列舉可以是輸入和輸出類型。
-
聯集/介面:聯集可讓您根據用戶端請求的資料,在請求中傳回一或多個物件。例如,如果您的Book類型具有 title 欄位,Author而類型具有 name 欄位,則可以在這兩種類型之間建立聯集。如果您的用戶端想要查詢資料庫以取得片語「Julius Caesar」,則聯集可以從 傳回 Julius Caesar (William Shakespeare 的播放),Booktitle並從 傳回 Julius Caesar Author ( Commentarii de Bello Gallico 的作者)name。聯集只能是輸出類型。
介面是 物件必須實作的一組欄位。這與 Java 等程式設計語言的界面略有相似,您必須在其中實作界面中定義的欄位。例如,假設您建立了名為 的界面Book,其中包含 title 欄位。假設您稍後建立了名為 的類型Novel,該類型已實作 Book。您的 Novel必須包含 title 欄位。不過,您的 Novel 也可以包含不在 介面中的其他欄位,例如 pageCount或 ISBN。介面只能是輸出類型。
以下各節將說明每種類型如何在 GraphQL 中運作。
物件
GraphQL 物件是您將在生產程式碼中看到的主要類型。在 GraphQL 中,您可以將物件視為不同欄位的群組 (類似於其他語言的變數),每個欄位都由可保留值的類型 (通常是純量或其他物件) 定義。物件代表可從您的服務實作擷取/控制的資料單位。
使用 Type關鍵字宣告物件類型。讓我們稍微修改結構描述範例:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
此處的物件類型為 Person和 Occupation。每個物件都有自己的欄位和自己的類型。GraphQL 的一項功能是能夠將欄位設定為其他類型。您可以在 中看到 occupation 欄位Person包含 Occupation 物件類型。我們可以建立此關聯,因為 GraphQL 只描述資料,而不是服務的實作。
純量
純量基本上是保留值的基本類型。在 中 AWS AppSync,純量有兩種類型:預設 GraphQL 純量和 AWS AppSync 純量。純量通常用於在物件類型中存放欄位值。預設 GraphQL 類型包括 Int、Float、Boolean、 String和 ID。讓我們再次使用上一個範例:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
type Occupation {
title: String
}
轉出 name和 title 欄位,兩者都保留純量。 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定義用戶端對伺服器提出請求的所有進入點。Query 您的 GraphQL 實作中一律會有 。
以下是我們在先前結構描述範例中使用的 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並傳回 people(Person物件清單) 和 occupations(Occupation物件清單)。在 中people,我們只會傳回每個 name的欄位Person,同時傳回每個 title的欄位Occupation。回應可能如下所示:
{
"data": {
"people": [
{
"name": "John Smith"
},
{
"name": "Andrew Miller"
},
.
.
.
],
"occupations": [
{
"title": "Firefighter"
},
{
"title": "Bookkeeper"
},
.
.
.
]
}
}
範例回應顯示資料如何遵循查詢的形狀。擷取的每個項目都會列在 欄位的範圍內。 people和 occupations會以個別的清單傳回物件。雖然有用,但修改查詢以傳回人員名稱和職業清單可能更為方便:
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是欄位名稱;id、 name和 age是參數; Person是傳回類型。回顧 Person類型:
type Person {
id: ID!
name: String
age: Int
occupation: Occupation
}
我們已新增 occupation 欄位。不過,我們無法將此欄位Occupation直接設定為 ,因為物件無法做為引數傳入;它們是嚴格輸出類型。我們應該改為傳遞具有與 引數相同欄位的輸入:
input occupationInput {
title: String
}
我們也可以在建立新Person執行個體時,輕鬆更新我們的 addPerson 以包含此參數:
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
}
}
}
此變動稱為 createPerson,而 addPerson是 操作。若要建立新的 Person,我們可以輸入 id、age、 name和 的引數occupation。在 範圍內addPerson,我們也可以看到其他欄位age,例如 name、 等。這是您的回應;這些是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,將任務標題新增至資料來源,我們可以在 之後的變動中呼叫此 addPerson。 addPerson會先處理,再處理 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,操作為 personAdded。 personAdded會傳回新Person執行個體的 id和 name 欄位。查看變動範例,我們使用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列舉時,引數只能是 solidRed、solidYellow、 solidGreen(等)。使用列舉來描述具有不同但有限選擇數量的物件是很常見的。
聯集/界面
請參閱 GraphQL 中的界面和聯集。 GraphQL