graphql / graphql/graphql-spec

Proposal: Serial fields (nested mutations)

Open
#252 21 comments 135 reactions 0 assignees View on GitHub
💭 Strawman (RFC 0)
Dominant language
JavaScript
Stars
14.6k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

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]](https://facebook.github.io/graphql/#sec-Normal-and-Serial-Execution).

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:

```graphql
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:

```graphql
{
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:

```graphql
{
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:

```graphql
{
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` and `secondComments` 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! 😊

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.