Search code examples
c#graphqlhotchocolate

What is the best practise to make parallel calls on GraphQL query?


I am learning GraphQL using hotChocolate. I am trying to understand what is the best practice to achieve parallel calls on Query. Right now, I am playing with very small data (< 10 records) to learn basic concepts. But let's say tomorrow I have records in thousands, what is the best approach?

This approach works right now. This is more of a "what is best practice?" question.

  • What are the use cases where I need parallel calls? (rather than using GetById)

Query.cs

using GraphQlHotChocolate.Data;
using GraphQlHotChocolate.Services;

namespace GraphQlHotChocolate.Resolver;

public class Query
{
    private readonly IUser _userService;
    public Query(IUser userService)
    {
        _userService = userService;
    }
   
    public Task<User> GetUserById(string id, string userId) => _userService.GetUserById(id, userId);
}

Service.cs

using System.Text.Json;
using Microsoft.Azure.Cosmos;
using User = GraphQlHotChocolate.Data.User;

namespace GraphQlHotChocolate.Services;

public interface IUser
{
    Task<User> GetUserById(string id, string userId);
}

public class UserService : IUser
{
    private readonly CosmosClient _client;
    private readonly IConfiguration _config;
    
    public UserService(CosmosClient client, IConfiguration config)
    {
        _client = client;
        _config = config;
    }
    
    public async Task<User> GetUserById(string id, string userId)
    {
        try
        {
            var dbName = _config.GetValue<string>("Cosmos:DbName");
            var containerName = _config.GetValue<string>("Cosmos:UserContainer");
            
            var test = await _client.GetContainer(dbName, containerName)
                .ReadItemStreamAsync(id, new PartitionKey(userId));
            
            var user = test.IsSuccessStatusCode 
                ? await JsonSerializer.DeserializeAsync<User>(test.Content) 
                : default;
            
            return user;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }
}

Program.cs

using GraphQlHotChocolate.Resolver;
using GraphQlHotChocolate.Services;
using Microsoft.Azure.Cosmos;

var builder = WebApplication.CreateBuilder(args);

// Add Cosmos.
builder.Services.AddSingleton(_ => new CosmosClient(builder.Configuration["Cosmos:ConnectionString"]));

builder.Services.AddControllers();

builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>();

builder.Services.AddTransient<IUser, UserService>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapGraphQL();
});

app.Run();

Results:

Parallel Calls Parallel Calls

Regular Call Regular Call


Solution

  • Just add another query field. e.g.: usersByIds(ids: [String!]!): User[]

    Also, you will have a lot of headache with client library if your id is not your id. so if possible rename the userId to id and the id to whatever 111 is.