本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
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 的播放),Book
title
並從 傳回 Julius Caesar Author
( Commentsarii 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 只會描述資料,而不是服務的實作。
純量
Scalars 基本上是保留值的原始類型。在 中 AWS AppSync,純量有兩種類型:預設 GraphQL 純量和 AWS AppSync 純量。Scalars 通常用於在物件類型中存放欄位值。預設 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
定義針對伺服器提出請求之用戶端的所有進入點。您的 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
並傳回 people
(Person
物件清單) 和 occupations
(Occupation
物件清單)。在 中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
是欄位名稱;id
、 name
和 age
是參數; 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
}
}
}
此突變稱為 createPerson
,addPerson
是 操作。若要建立新的 Person
,我們可以輸入 id
、、 name
age
和 的引數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
,將任務標題新增至資料來源,則在 之後,我們可以在 突變中呼叫此 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
等 (enum)。使用列舉來描述具有不同但有限選擇數量的物件是常見的。
連線/介面
請參閱 GraphQL 中的介面和聯合。