Skip to content

Proposal: Serial fields (nested mutations) #252

Open
@syrusakbary

Description

@syrusakbary

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 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! 😊

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions