變動 Mutation
mutation 必須在 schema 中定義。與 query 一樣,我們要在 schema 內,用 mutation 自訂的物件型態定義它。技術上,在 schema 中定義 mutation 與 query 的方式沒有任何差異。有差異的是它們的目的。你只需要在動作或事件會改變有關於 app 的狀態時建立 mutation。
mutation 代表 app 的動詞,它們只應該包含使用者可以用你的服務做的事情。當你設計 GraphQL 服務時,可列出使用者可以用你的 app 做的所有動作,它們可能都是你的 mutation。
在 PhotoShape app 中,使用者可以登入、貼出照片與標記照片。這些動作都會改變一些 app 的狀態。當使用者登入後,用戶端的使用者就會改變。當使用者貼出照片時,系統會多出一張照片。有人標記照片時也會改變狀態,每當有照片被標記時,就會產生新的照片標記資料紀錄。
我們可以將這些 mutation 加入 schema 內的根 mutation 型態,讓用戶端可以使用他們。我們從第一個 mutation postPhoto 開始寫起。
1 | type Mutation { |
在 Mutation 型態下面加入一個稱為 postPhoto 的欄位可讓使用者貼出照片。目前只是詮釋這個動作,還需要 GraphQL 服務的實作。
當使用者貼出照片時,至少需要提供照片的 name,而 description 與 category 是可選的。如果使用者沒有提供 category 引數,貼出的照片將會使用預設值 PROTRAIT。例如,使用者可以傳送下列的 mutation 來貼出照片:
1 | mutation { |
使用者可以在貼出照片後選擇關於剛才貼出的照片的資訊。這是很好的功能,因為有些新照片資料是在伺服器上產生的,例如新照片的 ID 是資料庫建立的,照片的 url 是自動生成的,我們也會幫照片加上它被 created 建立時的日期與時間時戳。照片被貼出之後,query 可以選擇以上所有新欄位。
此外,選擇組也有關於貼出照片的使用者資訊。使用者必須登入才能貼出照片。如果目前沒有登入的使用者,這個 mutation 就要回傳錯誤。如果有使用者登入了,我們可以透過 postedBy 欄位來取得關於誰貼出照片的資料。
輸入型態 Input
你或許已經發現,有一些 query 與 mutation 的引數愈來愈長了。有一種調整這些引數的好方法,使用輸入型態。輸入型態類似 GraphQL 物件型態,但他只供輸入引數使用。
1 | input PostPhotoInput{ |
PostPhotoInput 型態就像物件型態,但是只供輸入引數使用。這裡 name 與 description 是必須的,但 category 欄位仍然是選用的。現在當你傳送 postPhoto mutation 時,要將新照片的相關資料放在一個物件裡面:
1 | mutation newPhoto($input: PostPhotoInput!) { |
我們建立這個 mutation 時,將 $input 查詢變數的型態設成 PostPhotoInput! 輸入型態。它不可為 null,因為我們至少要用 input.name 欄位來加入新照片。當我們傳送這個 mutation 時,必須用 input 欄位內的查詢變數(Query Variables)來提供新照片的資料:
1 | { |
我們的輸入被一起放在一個 JSON 物件裡面,並且在 “input” 鍵底下以 query 變數與 mutation 一起送出。因為查詢變數被格式化為 JSON,category 必須是個符合 PhotoCategory 的其中一種分類的字串。
輸入型態是建構與編寫簡明的 GraphQL schema 的關鍵元素。你可以將輸入型態當成任何欄位的引數,也可以在 app 中用它們來改善資料分頁與資料過濾。
回傳型態
現在 schema 的所有欄位都回傳主要的型態,User 與 Photo。但除了實際的承載資料 (payload data) 之外,有時我們也需要回傳關於 query 與 mutation 的詮釋資訊。例如,如果有使用者已經登入並且通過驗證了,除了 User 承載資料之外,我們也需要回傳權杖 (token)。
1 | type AuthPayload { |
我們藉由傳送有效的碼給 adAuth mutation 來驗證使用者,成功後,回傳一個自訂的物件型態,裡面有成功登入的使用者的資訊,可用來做進一步授權的權杖,以及包括 postPhoto mutation 的多個 mutation 時所需的使用者資訊。
你可以在任何 “需要除了承載資料之外的資料” 的欄位使用自訂回傳型態。或許除了尋承載資料之外,我們也想要知道一個 query 需要多少時間來傳遞回應,或是在某個回應中可找到多少結果。你可以使用自訂的回傳型態來處理這類的事情。
訂閱 Subscription
Subscription 型態與 GraphQL schema 定義語言的任何其他物件型態沒有甚麼不同。我們要在自訂物件型態內將 subscription 定義成欄位。而當建立 GraphQL 服務時,要自行確保 subscription 實作了 PubSub 設計模式以及一種即時傳輸。
例如,我們可以加入 subscription 來讓用戶端監聽 Photo 或 User 型態的建立:
1 | type Subscription { |
我們在這裡建立一個自訂的 Subscription 物件,它有兩個欄位: newPhoto 與 newUser。當使用者貼出新照片時,那張照片會被推送到訂閱 newPhoto subscription 的所有用戶端。有新的使用者被建立時,他們的資料會被推送到每一個監聽新使用者的用戶端。
subscription 與 query 或 mutation 一樣可以使用引數。假如我們要在 newPhoto subscription 加入過濾器,讓它只監聽新的 ACTION 照片:
1 | type Subscription { |
現在當使用者訂閱 newPhoto subscription 時,他們可以過濾被送到這個 subscription 的照片。例如,若要濾出新的 ACTION 照片,用戶端可傳送下列的操作給 GraphQL API:
1 | subscription { |
這個訂閱只會回傳 ACTION 照片的資料。
如果即時處理資料是很重要的功能,訂閱是很好的解決方案。