hotchoc - supporting different schema/types for code first and implementation approach

This shows an example of using implementation approach for hotchoc graphql. 

It shows how we can expose different type/schema using 2 different approaches namely

- implementation first 

- code first


In the implementation approach, it is straight forward. We setup the root query (that's a pre-requisite - can't have more than one root query for single graphql or federate graphql - typically you use extend for this)

Then, we add the relevant Type - The type here can be confusing. To me, it is classes that contains method which retrieves types and these types can be book, author. Hotchoc can automatically infer these types.


using apollo_gateway.Types;
using apollo_gateway.Types.CodeFirst;

var builder = WebApplication.CreateBuilder(args);

// implementation approach
builder.Services.AddGraphQLServer().AddApolloFederation().AddQueryType(q => q.Name("Query"))
    .AddType<BookDataReturnDataHelper>().AddType<ProductDataReturnDataHelper>();

var app = builder.Build();

app.MapGraphQL();

app.RunWithGraphQLCommands(args);


As you can see, we have decorate the classes with ExtendObjectType.

namespace apollo_gateway.Types;

[ExtendObjectType("Query")]

public class BookDataReturnDataHelper
{
    public Book GetBook()
        => new Book("C# in depth.", new Author("Jon Skeet"));
}

[ExtendObjectType("Query")]
public class ProductDataReturnDataHelper
{
    public Product GetProduct()
        => new Product("C# in depth.", new Author("Jon Skeet"));
}


Code first approach

In the code first approach we had similar setup but for blog and comments. In program.cs, we would need the following code to  tied it all up. 


// implementation approach
builder.Services.AddGraphQLServer().AddApolloFederation().
AddQueryType<BlogQueryType>();


Next we have the code that get us all the data, exactly the same as 'BookDataReturnDataHelper' above.
Here we expose 2 different types of type/schema called Comment and Blog.


public class BlogQueryType : ObjectType<CodeFirstDataRetriver>
    {
        protected override void Configure(IObjectTypeDescriptor<CodeFirstDataRetriver> descriptor)
        {
            descriptor
                .Field(f => f.GetBlog())
                .Type<BlogType>();

            descriptor
                .Field(f => f.GetComment())
                .Type<CommentType>();
        }
    }


Next we definite the schema for both object above. Maybe calling it CommentSchema or BlogSchema can help to make it more clear.


public class CommentType : ObjectType<Comment>
    {
        protected override void Configure(IObjectTypeDescriptor<Comment> descriptor)
        {
            descriptor
                .Field(f => f.Id)
                .Type<StringType>();

            descriptor
                .Field(f => f.UserInput)
                .Type<StringType>();
        }
    }

    public class BlogType : ObjectType<Blog>
    {
        protected override void Configure(IObjectTypeDescriptor<Blog> descriptor)
        {
            descriptor
                .Field(f => f.Id)
                .Type<StringType>();

            descriptor
                .Field(f => f.UserInput)
                .Type<StringType>();
        }
    }


Both approach is similar in a way. I don't really like code first approach as the code get cluttered in a single file and does help with separation of concerns. Definitely prefer the implementation approach.

You can find the actual code here

https://github.com/mitzenjeremywoo/hotchoc_multiple_type_support_implementation_approach


Comments

Popular posts from this blog

gemini cli getting file not defined error

NodeJS: Error: spawn EINVAL in window for node version 20.20 and 18.20

vllm : Failed to infer device type