GraphQL on Rails(一) GraphQL介紹
GraphQL on Rails(二) 結(jié)合Rails的查詢API
接著上一個(gè)寫(xiě)到的GraphQL在RailsAPI應(yīng)用中的查詢功能褪那,這次我們來(lái)實(shí)現(xiàn)修改數(shù)據(jù)的功能痢缎,修改數(shù)據(jù)的操作在GraphQL中被稱為 突變(mutation即修改數(shù)據(jù)),它在GraphQL schema中的定義是這樣的钢颂。
QuerySchema = GraphQL::Schema.new(mutation: TODO)
我們還是延續(xù)上一篇的例子,一個(gè)博客系統(tǒng)白嘁,其中包含三個(gè)模型:Article心墅、User 、Comment持灰。
突變
mutation在GraphQL中與其他元素一樣也是一個(gè)類(lèi)型的定義盔夜,那么既然是類(lèi)型的定義,我們就可以將它存放在 types目錄下面堤魁,:
MutationType = GraphQL::ObjectType.define do
# TODO
end
然后就像上面提到的那樣喂链,我們需要在schema定義中指定需要加載的mutation
QuerySchema = GraphQL::Schema.new(query: QueryType, mutation: MutationType)
接下來(lái)我們就編寫(xiě) MutationType中的內(nèi)容,定義一下具體可以操作的數(shù)據(jù)類(lèi)型妥泉。既然構(gòu)建的是博客系統(tǒng)那么系統(tǒng)是要提供椭微,對(duì)文章的發(fā)布和修改,以及對(duì)文章記性評(píng)論涛漂,和違禁評(píng)論的刪除功能赏表。
MutationType = GraphQL::ObjectType.define do
field :CreateArticle, field: ArticleMutations::Create
field :UpdateArticle, field: ArticleMutations::Update
field :CreateComment, field: CommentMutations::Create
field :DestroyComment, field: CommentMutations::Destroy
end
現(xiàn)在MutationType中就已經(jīng)有了這四種操作的類(lèi)型,可以看到上面的每一行定義中存在兩個(gè)field關(guān)鍵字匈仗,這其中第一個(gè)field是我們定義的MutationType的字段名瓢剿,后面的Symbol field才是正在的類(lèi)型定義存在的地方,當(dāng)然如果你愿意的話其實(shí)可以將它們直接寫(xiě)在 MutationType的定義當(dāng)中的悠轩,但是因?yàn)槌绦驈?fù)雜起來(lái)后间狂,像上面的這種寫(xiě)法更容易模塊化,所以使用這種寫(xiě)法火架。
我們將上面提到的四個(gè)mutations的文件存放在對(duì)應(yīng)的./app/graph/mutations 中
├── app
│ ├── graph
│ │ ├── fields
│ │ ├── schemas
| | ├── mutations
│ │ └── types
**app/graph/mutations/article_mutations.rb **
module ArticleMutations
Create = GraphQL::Field.define do
type -> { ArticleType }
description 'create a article'
argument :title, !types.String
argument :content, !types.String
resolve -> (obj, input_fields, ctx) do
ctx[:current_user].articles.create(title: input_fields['title'], content: input_fields['content'])
end
end
Update = GraphQL::Field.define do
type -> { ArticleType }
description 'update title of article'
argument :id, types.ID
argument :title, !types.String
resolve -> (obj, input_fields, ctx) do
article = Article.find_by(id: input_fields['id'])
article.update(title: input_fields['title'])
article
end
end
end
**app/graph/mutations/comment_mutations.rb **
module CommentMutations
Create = GraphQL::Field.define do
type -> { CommentType }
description 'create a comment of article'
argument :article_id, types.ID
argument :content, !types.String
resolve -> (obj, input_fields, ctx) do
article = Article.find_by(id: input_fields['article_id'])
article.comments.create(content: input_fields['content'], user: ctx[:current_user])
end
end
Destroy = GraphQL::Field.define do
type -> { types.Boolean }
description 'delete a comment'
argument :id, types.ID
resolve -> (obj, input_fields, ctx) do
!!Comment.delete(input_fields['id'])
end
end
end
從上面的兩段代碼看到鉴象,mutation其實(shí)和query是基本一樣的類(lèi)型定義忙菠,首先由type指定修改數(shù)據(jù)后的返回值類(lèi)型,argument定義可以傳遞的參數(shù)纺弊,resolve 方法的block參數(shù)是最后具體執(zhí)行操作的代碼牛欢。其中還有一個(gè)需要注意的就是 resolve 方法中的第三個(gè)參數(shù),ctx (context) 它是用于存放controller中傳遞進(jìn)來(lái)的上下文數(shù)據(jù)淆游,我們這個(gè)博客系統(tǒng)的創(chuàng)建數(shù)據(jù)操作都需要用戶信息所以傍睹,需要在controller中把當(dāng)前用戶傳進(jìn)來(lái)。
class QueriesController < ApplicationController
def create
result = ::QuerySchema.execute(params[:query], context: {current_user: current_user})
render json: result
end
end
接下來(lái)犹菱,讓我們來(lái)創(chuàng)建一個(gè)文章看看效果:
文章被創(chuàng)建成功拾稳,并且返回了作者的ID以及,文章的ID和標(biāo)題腊脱。
總結(jié)
通過(guò)上面的實(shí)例访得,我們可以看出GraphQL中不管是查詢還是突變都保持著統(tǒng)一的類(lèi)型系統(tǒng)的樣子,其中有要注意的幾點(diǎn)是:突變字段中的 resolve方法的返回值的類(lèi)型要和聲明的類(lèi)型一致陕凹,還有就是多個(gè)突變操作在一個(gè)查詢中是順序執(zhí)行的悍抑。
后面的話這一系列文章會(huì)寫(xiě)到GraphQL的其他高級(jí)功能在Rails中的應(yīng)用,以及GraphQL查詢的優(yōu)化方案等杜耙。