ArchitectureUsing a single source of code for standard and nested mutations

Using a single source of code for standard and nested mutations

The GraphQL server supports 2 behaviors:

  1. The standard behavior for mutations, by default
  2. Nested mutations, as an opt-in

As a consequence, it will expose types QueryRoot and MutationRoot by default, and switch to exposing a single Root type for nested mutations.

When providing the resolvers, we wouldn't want to provide two resolvers, one for each solution. It's better that the same resolver used to resolve fields for Root can also resolve fields from QueryRoot and MutationRoot.

Implementation details

The server uses an object called FieldResolver to resolve fields, and an object called MutationResolver to execute the actual mutation. The same MutationResolver object can be referenced by different FieldResolvers implementing different fields, so the code is implemented only once and used in many places, following the SOLID approach.

We know if a field is a mutation or not if the FieldResolver declares a MutationResolver object for that field, done through function resolveFieldMutationResolverClass.

For instance, field Root.replyComment provides object AddCommentToCustomPostMutationResolver. This same object is also used by field Comment.reply.

Furthermore, when coding the FieldResolver, the root fields are added to the Root type only. For the standard GraphQL behavior, the server can retrieve this configuration, and automatically add these fields to either MutationRoot or QueryRoot depending on if they are mutations or not.

As a result, since we are using a single source for the code powering both the standard behavior and nested mutations, we are able to execute queries with nested mutations for no extra effort.