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)