變更(Mutations)
學習如何用 GraphQL 伺服器修改資料
大多數關於 GraphQL 的討論都聚焦在資料查詢,但任何完整的資料平台都需要能夠修改伺服器端資料的方式。
在 REST 中,任何請求都有可能對伺服器產生副作用,但依照慣例,建議不要用 GET
請求來修改資料。GraphQL 也很類似——技術上來說,任何欄位解析器都可以實作成寫入資料,但GraphQL 規範明確指出:「除了最上層 mutation 欄位以外,其他欄位的解析必須是無副作用且具冪等性的。」因此,對於任何符合規範的 GraphQL schema,只有 mutation 操作的最上層欄位允許產生副作用。
本頁會教你如何用 mutation 操作來寫入資料,並且以支援客戶端需求的方式來設計。
所有查詢操作適用的 GraphQL 功能,在 mutation 也都適用,所以建議先閱讀查詢(Queries)頁面再繼續。
新增資料(Add new data)
在 REST API 中建立新資料時,通常會送出 POST
請求到特定 endpoint,並在請求主體中帶上要建立的實體資訊。GraphQL 則採用不同的方式。
我們來看一個 schema 中定義的 mutation 範例:
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
input ReviewInput {
stars: Int!
commentary: String
}
type Mutation {
createReview(episode: Episode, review: ReviewInput!): Review
}
和查詢一樣,mutation 欄位會加在根操作類型之一,作為 API 的進入點。本例中我們在 Mutation
類型上定義了 createReview
欄位。
mutation 欄位也可以接受參數,你會注意到 review
參數的型別是 ReviewInput
,這就是所謂的 Input Object type,可以讓我們傳遞一個結構化物件,而不只是單一的 scalar 值。
同樣地,如果 mutation 欄位回傳的是物件型別,你也可以在操作中指定欄位選擇集:
# { "graphiql": true, "variables": { "ep": "JEDI", "review": { "stars": 5, "commentary": "This is a great movie!" } } }
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
雖然 createReview
欄位可以定義成 schema 中任何合法的輸出型別,但慣例上會指定與這次變更有關的型別——這裡是 Review
。這對於需要在更新後取得物件新狀態的客戶端很有幫助。
請記住,GraphQL 設計是為了能和你現有的程式碼與資料整合,所以實際建立評論的動作要由你在伺服器端實作。當客戶端送出這個操作時,伺服器端可能會有像這樣的函式來寫入資料庫:
const Mutation = {
createReview(_obj, args, context, _info) {
return context.db
.createNewReview(args.episode, args.review)
.then(reviewData => new Review(reviewData));
},
};
你可以在執行(Execution)頁面了解 GraphQL 如何為欄位提供資料。