Skip to main content
2 of 2
edited title
k29
  • 109
  • 4

GraphQL results in a very large Query and Mutator file for Enterprise Monolith

I am investigating a good maintainable architecture for GraphQL. In particular we want to migrate a REST app to GraphQL. Specifically I am using .NET.

I am following the tutorial here: https://fullstackmark.com/post/17/building-a-graphql-api-with-aspnet-core-2-and-entity-framework-core
which is very similar to most tutorials

It has the following Mutator file:

public class NHLStatsMutation : ObjectGraphType
{
   public NHLStatsMutation(IPlayerRepository playerRepository)
   {
     Name = "Mutation";

     Field<PlayerType>(
           "createPlayer",
           arguments: new QueryArguments(
           new QueryArgument<NonNullGraphType<PlayerInputType>> { Name = "player" }
     ),
     resolve: context =>
     {
        var player = context.GetArgument<Player>("player");
        return playerRepository.Add(player);
     });
   }
}

This gets assigned in the schema:

public class NHLStatsSchema : Schema
{
  public NHLStatsSchema(IDependencyResolver resolver): base(resolver)
  {
     Query = resolver.Resolve<NHLStatsQuery>();
     Mutation = resolver.Resolve<NHLStatsMutation>();
  }
}

Finally there is a single GraphQLController which handles the API requests and has an instance of the schema:

    [Route("[controller]")] 
    public class GraphQLController : Controller
    {
        private readonly IDocumentExecuter _documentExecuter;
        private readonly ISchema _schema;

        public GraphQLController(ISchema schema, IDocumentExecuter documentExecuter)
        {
            _schema = schema;
            _documentExecuter = documentExecuter;
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
        {
            if (query == null) { throw new ArgumentNullException(nameof(query)); }
            var inputs = query.Variables.ToInputs();
            var executionOptions = new ExecutionOptions
            {
                Schema = _schema,
                Query = query.Query,
                Inputs = inputs
            };

            var result = await _documentExecuter.ExecuteAsync(executionOptions).ConfigureAwait(false);

            if (result.Errors?.Count > 0)
            {
                return BadRequest(result);
            }

            return Ok(result);
        }
    }
}

Having a single schema and API endpoint seems to be "How GraphQL is done" according to a few parts of the internet.

However this seems to result in a very very large Query and Mutator file, with many many dependencies injected (repositories, services etc) and many, many methods in the file.

This is an Enterprise applicattion with 300+ database tables and lots of complex backend business rules. The application is a monolith with a layered architecture with a UI layer, Services layer and Data Layer.

How can I architect this to make this more maintainable?

I have read up on Schema Stitching or Federation (https://www.apollographql.com/docs/graphql-tools/schema-stitching/) However, I'm not sure if that's the right approach as the examples seem to be using that to address microservices or API endpoints from different apps. (https://blog.apollographql.com/graphql-schema-stitching-8af23354ac37)

k29
  • 109
  • 4