Description
In the current GraphQL specification the schema type have three different types on it: query
, mutation
and subscription
.
The mutation type is a special ObjectType
that enforces the fields on it to be resolved serially
instead of in often parallel
as could happen in fields in any other type
When executing a mutation, the selections in the top most selection set will be executed in serial order. [1].
But this "mutation" type declaration is not self-contained: when defined in a schema as mutation it have a side effect on the execution of a query, making their fields to be executed serially.
Because of there is only one type in a schema that enforces a serial evaluation on their subfields, all "mutation fields" are forced to be in the Mutation type itself.
Having all "serial resolved fields" in only one types causes the Mutation type (schema.mutation) to be an ObjectType
with over bloated fields on it, that have not common ground between them other than serial execution.
Proposal
Would be great if instead of having all the mutations in a first type class (where it's execution depends on the Schema for knowing if it should be resolved serially or not), we could be able to mutate in a generic GraphQL query, in any kind of type level.
Would be great, if instead of doing:
mutate MyMutation {
postToUserTimeline(userId: "1", commentContent: "Happy Birthday Mark!") {
comment { # The new created comment in Mark's timeline
id
content
}
user {
timeline {
id
content
}
}
}
}
We could be able to do serial resolution on certain fields:
{
getUser(id:"1") {
postToTimeline(commentContent:"Happy Birthday Mark!") { # serial field
comment {
id
}
}
allComments {
id
comment
}
}
}
Composing mutations
With the ability to have "mutation / serial fields" in any kind of type, we could start doing things like:
{
user(id:"1") {
postToTimeline(commentContent:"Happy Birthday Mark!") { # This is a serial field
comment {
addReaction(reaction: LIKE) # This is another serial field, that adds a reaction into the comment
}
}
}
}
Execution showcase
The following example hopefully will showcase how the field resolution could be done:
{
user(id:"1") {
postToTimeline # serial
comments # normal
photos # normal
tagPhoto # serial
postAgain: postToTimeline # serial
secondPhotos: photos # normal
secondComments: comments # normal
}
}
In this case, the execution will done serially as follows:
- Resolve
postToTimeline
(not resolve any other field until this is resolved) - Resolve
comments
,Photos
normally (often in parallel) - Resolve
tagPhoto
- Resolve
postAgain
- Resolve
secondPhotos
andsecondComments
normally (often in parallel)
How could be implemented
This could be easily solved by creating a adding a isMutation
(isSerial
maybe is better?) attribute inside the Field.
In the previous example, postToTimeline
will be executed serially first, then in parallel all the subsequent fields until another "serial field" (field with isSerial=true
on it) is found, and so on.
Why of this proposal
There is a lot of tooling that could be created specifically around mutations, and this would help a lot for it, apart from simplifying the schema execution (as are now will be the fields the ones that define if they want to be executed serially or not) and mutations composition.
Related issues: #247
There a lot of things to improve, define better and discuss further, so any thoughts and feedback is more than welcome! 😊