shujaat siddiqui
shujaat siddiqui

Reputation: 1577

Multiple Query Type in Graphql Hotchocolate

I am using hot chocolate graphql. I have a scenario where I have two separate query type classes.

  1. PostQuery -> contains post related queries
  2. UserQuery -> contains user related queries

My Folder Structure

enter image description here

Here it is how I am configuring it

 .AddAuthorization()
    //for inmemory subscription
    .AddInMemorySubscriptions()
    .AddQueryType<PostQuery>()
    .AddQueryType<UserQuery>()
    .AddMutationType<Mutation>()
    .AddSubscriptionType<Subscription>()
    .AddGlobalObjectIdentification()
    // Registers the filter convention of MongoDB
    .AddMongoDbFiltering()
    // Registers the sorting convention of MongoDB
    .AddMongoDbSorting()
    // Registers the projection convention of MongoDB
    .AddMongoDbProjections()
    // Registers the paging providers of MongoDB
    .AddMongoDbPagingProviders();

However, i am getting the following error

System.ArgumentException: The root type `Query` has already been registered

Is there anyway it can be configured or else I have to places everything in a single class?

Upvotes: 10

Views: 7363

Answers (3)

Paul Marshall
Paul Marshall

Reputation: 643

Just came across this post and have a slight variation on @sjokkogutten answer based on my implementation:

I am extending an existing service which already has a Query implementation:

public class TemplatesQuery
{
    public async Task<IQueryable<Template>> GetTemplates(
        [Service] ILogger<TemplatesQuery> logger,
        [Service] ITemplatesService templatesService)
    {
        ...
    }
}

To do this I am treating my subsequent Queries as extensions:

[ExtendObjectType(typeof(TemplatesQuery))]
public class SignaturesQuery
{
    public async Task<IQueryable<Signature>> GetSignatures(
        [Service] ILogger<SignaturesQuery> logger,
        [Service] ISignaturesService signaturesService)
    {
        ...
    }
}

and then registering the new service as a type extension:

builder.Services.AddGraphQLServer()
    .AddQueryType<TemplatesQuery>()
    .AddTypeExtension<SignaturesQuery>();

The result is the same as @sjokkogutten answer but it avoids having to define a "pretend" query type while maintaining separation of concerns for the different workflows. It also means if you have an existing service you want to extend that you don't have to mess with any existing code. Good old open close principal :)

Upvotes: 1

THE AMAZING
THE AMAZING

Reputation: 1593

First thanks to @sjokkogutten for his answer. I strongly disagree with his approach. As your application size gets larger your types will become more tedious to manage.

The better approach would be to define your queries in partial classes.

postQuery.cs

public partial class Query
{
    public List<Post> GetAllPosts()
    {
        return List<Post>{...};
    }
}

UserQuery.cs

public partial class Query
{
    public List<User> GetAllUsers()
    {
        return List<User>{...};
    }
}

Upvotes: 8

sjokkogutten
sjokkogutten

Reputation: 2095

You need to register the querytype "Query" and add resolvers to handle multiple schemas of type "Query"

builder.Services
.AddQueryType(q => q.Name("Query"))
.AddType<PostQuery>()
.AddType<UserQuery>()

And in your query classes:

[ExtendObjectType("Query")]
public class PostQuery 
{
    public List<Post> GetAllPosts()
    {
        return List<Post>{...};
    }
}

[ExtendObjectType("Query")]
public class UserQuery
{
    public List<User> GetAllUsers()
    {
        return List<User>{...};
    }
}

Upvotes: 23

Related Questions