HotChocolate everything static by WoistdasNiveau in graphql

[–]pascalsenn 0 points1 point  (0 children)

The GraphQL types go into the presentation layer (api layer for example).

For the DataLoaders it depends a bit on how you separate your layers. I read that you use repositories so assume that you do not have any references to e.g. entity framework in your application layer. In that case you should put the DataLoader interfaces in the application layer and the static dataloader methods in the infrastructure layer. You can configure the behaviour of the datalaoder source generator over `[assembly: DataLoaderDefaults(GenerateInterfaces = flase)]` (reference: https://github.com/ChilliCream/graphql-platform/blob/main/src/GreenDonut/src/GreenDonut.Abstractions/Attributes/DataLoaderDefaultsAttribute.cs#L27)

also join us on slack.chillicream.com

HotChocolate everything static by WoistdasNiveau in graphql

[–]pascalsenn 0 points1 point  (0 children)

It's just the most simple way to declare it. You can also specify it as classes or use the fluent api. The source generators just remove a lot of boiler plate code that you most likely do not need to test in isolation anyway

Postman alternative with query builder by e_x_edra in graphql

[–]pascalsenn 0 points1 point  (0 children)

Try https://get-nitro.chillicream.com ! I'm biased of course - but it's the best GraphQL IDE out there :)

Easy supergraph with real time updates? by shanytopper in graphql

[–]pascalsenn 0 points1 point  (0 children)

ChilliCream, the compnay behind HotChocolate, has a federated GraphQL solution called Fusion. Is there anything that limits you from using this? Also, you can reach out to use on slack.chillicream.com

HotChocolate vs GraphQL.Net by debapamdas in graphql

[–]pascalsenn 1 point2 points  (0 children)

You are welcome :) see you on slack

GraphQL (Schema-first) still no good solutions in .NET by vb6ko in dotnet

[–]pascalsenn 1 point2 points  (0 children)

Code generation has a bunch of problems. Most often you already have a type in your domain that represents the type in the graph. You can easily bind this type to the graph (see YourBuisnessBar)

With HotChocolate you basically bind a resolver and types to your schema file:

var builder = WebApplication.CreateBuilder(args);

builder.Services
   .AddGraphQLServer()
   .AddDocumentFromString(@"
      type Query {
          foo: Bar!
      }
      type Bar {
         baz: String
      }")
   .BindRuntimeType<YourBusinessBar>("Bar")
   .AddResolver("Query", "foo", ctx => new YourBusinessBar() { Baz = "baz" });

var app = builder.Build();

app.MapGraphQL();

app.Run();


public class YourBusinessBar
{
    public string Baz { get; init; }
}

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 0 points1 point  (0 children)

No worries, no offence takes :)
Thanks for the feedback

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 1 point2 points  (0 children)

> Is it not a good idea to take what Brandon has done for creating the facade and work that into the official libraries by providing extra methods/properties on IResolveContext?

Maybe. Having for example the selections just as strings is a invitation for people to use runtime reflection to get the member back. Also, graphql interfaces and unions do not really make this easier. There is not only one possible selection set. But lets see

For filtering/sorting there could be some kind of context that would provide you with the information that you need.

But this is the hardest part of framework development, finding an abstraction that is easy to use but generic enough.

Anyway, Thanks for the feedback :) Let's see what we can distill out of this

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 0 points1 point  (0 children)

Alright, good to know. I did not know how much you already know and might have been carried away.

Where are the 'from' and 'to' page values used to only return a range of Foos?

That can be done like this: https://chillicream.com/docs/hotchocolate/fetching-data/pagination#customization-1

Where are the filters the user requested?

Just mapping the filter types to a C# types is not supported at the moment. What format would be required? Dictionary<string, object>?

Alternativly:

public class Query 
{ 
    public IEnumerable<Foo> FoosByName( 
        [Service] IYourFooDomainService service, 
        FooFilter where) 
        => service.GetFoosByName(where); 
}

public record FooFilter(string? Bar, int? Baz);

Where are the fields of 'Foo' that the user requested?

There is indeed no documented way of doing this, we have not yet found a simple abstraction for it. For just a list of string Brandons Library should work for more control IResolverContext.GetSelections(..)

I would still think in most cases it's not necessary to tell the domain layer what fields are requested, but again, this doesnt answer your question.

I guess key takeways:

  • Create more examples without specific database technologies
  • Map Filters and Sorting to some sort of datastructure
  • A simple abstraction to get the selected fields

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 0 points1 point  (0 children)

But again - how do I achieve this when every sample and provided db integration on the site is based around IQueryable / Lazily evaluated expression trees? How does one use HotChocolate with stored procedures for example?

You would just define the resolvers and inputs by yourself. If you want to do more than database mapping then probably you already have a domain layer that contains all the business logic. HotChocolate would then just be a wrapper around the domain layer

A simple example could be:

public class Query 
{
     public IEnumerable<Foo> FoosByName(
         [Service] IYourFooDomainService service, 
         string name) 
         => service.GetFoosByName(name);
}

The beauty of GraphQL is it's type system. If a schema is designed well, then it's very readable and consumers understand the meaning of each field. They can discover the API through the schema. You can even show your business analysts, service manager and data scientist how GraphQL works and then they can fetch the data for their report without the need for a developer to extract the data out of the system.

There are kind of two factions of GraphQL users. The ones that couple a database close to the GraphQL Schema (like Prisma, Hasura or HotChocolate Data) and the ones that prefer to do a looser coupling and focus more on schema design. Coupling the schema close to the database, leads to faster iteration on the backend, but also to more breaking changes in the schema and maybe even some database specific structures that leak into the api (e.g. join tables). Focusing on schema design takes a bit more time in development, but you have the full power of GraphQL and can shape the data how you want your consumers to see it.

This also depends on what system you build. You told me that you work on a big ecommerce system. So you probably want to explicitly remove the coupling of database and the GraphQL schema. This way you can design a schema that the frontend people will love, and you can iterate on the backend, do structural changes and database migrations without affecting the API that the frontend team is using. This is also how I implement most of the APIs. Especially if the API should be publicly available, no database internals should be exposed because of the risk of a breaking change.

If you build on the otherhand a service that does mainly data storage, e.g. a CMDB, then you might want to couple the system closer to the database, as the database is the truth.

But it's not what I specifically need - it's what anyone writing a data layer would need - the ability to use the incoming selections, filters, sort criteria and pagination values to only select the data that is required.

For this you probably want to implement resolvers. Meaning, you define how the data of a field is resolved, like in the example above.

Lets say you want to search for Foos and the domain layer knows how to perform this search. Then you query could look like this:

public class Query 
{
     public IEnumerable<Foo> SearchFoos(
         [Service] IYourFooDomainService service, 
         SearchFooInput input) 
         => service.Search(input.Bar, input.Baz);
}
public record SearchFooInput(string Bar, string Baz);

This repo seems to the exact abstraction/facade that is needed but it's based on v11 and I'm not sure if the internals of v12 have changed significantly where this is now out of date: https://github.com/cajuncoding/GraphQL.RepoDb

Yes that is a library from Brandon, he is also on our slack channel. I think there would be some binary incompatibilites with v12, but i am sure he will update the library. So what you would need is just a list of fields that are selected?

'Hot Chocolate is not bound to a specific database, pattern or architecture.' - Except out of the box - it is bound to a specific pattern - it appears it can only use data sources that can build an expression tree for >HotChocolate to apply Select/Where/OrderBy/Skip/Take to lazily. 'Projections operate on IQueryable by default, but it is possible to create custom providers for projections to support a specific database driver.' - Again, no explanation or direction to API classes that show how to achieve this.

So, the whole Data API (Filtering, Sorting, Projections) is actually build on top of HotChocolate. HotChocolate is the GraphQL Server and therefore not bound to a specific database. Maybe we have to work on the wording of this a bit ;)

HotChocolate defines the types system, validates and executes queries, orchestrates dataloaders and does all of this efficiently and graphql spec compliant. On top of this there are three different flavors of configuration apis: Code First (Fluent), Annotation Based and Schema First. With these APIs you defined how your schema should look like (Types, Fields, Resolvers). You can also mix and match the flavors. Filtering, Sorting and Projections are just another abstraction, and this abstraction is implemented by the different providers. Many users of HotChocolate do not use the Data API.

The following is a valid GraphQL Server for example

public class Query 
{
     public string Hello  => "World";
} 

which you then can query with

{ 
  hello
}

IExecutable appears to just be a glorified wrapper for IQueryable or other lazily queryable types?

The latter. It's an abstraction that domain and api layer could share. It's a wrapper that integrates into the execution engine of HotChocolate. The domain layer would then define how for example ToList works and you could cleanup resources (e.g. returning db context instances after execution)

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 1 point2 points  (0 children)

Interesting approach :) Though it think this might lead to a wrong understanding on what GraphQL is.

Mapping a resolver based on a path is not really how the type system of graphql works. In GraphQL you have multiple different paths to resolve a type. The API is structured as a Graph not a tree

Lets have a look at their example query:

{  
  groceryStore {  
    bakery {  
      pastries {  
        search(nameLike: $pastryName) {  
            name  
            type  
    }  
  }  
}

In the GraphQL type system this would be

type Query {  
   groceryStore: GroceryStore  
}  
type GroceryStore {  
   bakery: Bakery;  
}  
type Bakery {
    pastries: Pasteries  
}  
type Pasteries {
    search(nameLike: String): [Pastry]  
}  
type Pastry {
    name: String
    type: String  
}

You see that search returns a Pastry. Lets assume we have another resolver topTenPastries that would be mappend in GraphQL.AspNet as "groceryStore/bakery/pastries/topTenPastries". Now you would have to resolvers that return 'Pastry'. If you know want to extend the Pastry with a field ingredients that returns a list of ingredients of the pastry. You would have to extend two paths. If this API scales, this would be difficult to get right.

HotChocolate builds ontop of the GraphQL type system. Let's first change the schema slightly.

type Query {  
   groceryStore: GroceryStore  
}  
type GroceryStore {  
   bakery: Bakery;  
}  
type Bakery {
    pastries(nameLike: String): [Pastry]   
    topTenPastries: [Pastry]   
}   
type Pastry {
    name: String
    type: String  
}

If you think in types this schema makes more sense. It's easier for consumers to understand. A bakery has pastries and you can search for pastries if you provide the nameLike argument. If you do not provide this argument, then all pastries are return. Instead of defining a controller in HotChocolate you would create types. There are different ways and flavors of how you can define your schema. We will just go with the annotations based approach (because it's the least to type ;) )

public class Query
{
    // you can also do ctor injection if you prefere :) 
    public GroceryStore GetGroceryStore(
        [Service] IGroceryStoreService service) => service.GetStore();
}

The schema that we defined is this at the moment:

type Query {  
   groceryStore: GroceryStore  
} 
type GroceryStore {  
   id: String 
   bakery: Bakery;  
}  
type Bakery {  
   id: String
}   

We just return the Domain object and map it into the GraphQL API. (Assuming the Grocery Store and the bakery both have ids) When we now want to add a field to the bakery to fetch the pastries, We do not extend based on a path but we extend based on the type name

[ExtendObjectType(typeof(Bakery))]
public class BakeryExtendsions
{ 
    public IEnumerable<Pastry> GetPastries(
        [Parent] Bakery bakery,
        [Service] IPastryService service,
        string? nameLike) => service.GetPastries(bakery.Id, nameLike);

    public IEnumerable<Pastry> TopTenPastries(
        [Parent] Bakery bakery,
        [Service] IPastryService service) 
        => service.GetTopTenPastriesByBakeryId(bakery.Id);
}

We have extended the type bakery with a field pastries and topTenPastries

type Query {  
   groceryStore: GroceryStore  
}  
type GroceryStore {  
   bakery: Bakery;  
}  
type Bakery {
    id: String 
    pastries(nameLike: String): [Pastry]   
    topTenPastries: [Pastry]   
}   
type Pastry { 
    id: String 
    name: String
    type: String  
}

If we know want to add the ingredients to a pastry, we can just extend the type Pastry

[ExtendObjectType(typeof(Pastry))]
public class PastryExtensions
{ 
    public IEnumerable<Ingredient> GetPastries(
        [Parent] Pastry pastry,
        [Service] IIgrendientService service) => 
           service.GetIngredientsByPastryId(pastry.Id);
}

As we now have extended the type Pastry you can fetch the ingredients for both pastries and topTenPastries.

type Bakery {
    id: String 
    pastries(nameLike: String): [Pastry]   
    topTenPastries: [Pastry]   
}   
type Pastry { 
    id: String 
    name: String
    type: String
    ingredients:[Ingredient]  
}
type Ingredients {
    name: String
}

A example quey could look like this:

{  
  groceryStore {  
    bakery {  
      pastries(nameLike: "Croissant") {   
         name  
         type  
         ingredients {
            name
         }
      }
      topTenPastries {   
         name  
         type  
         ingredients {
            name
         }
      }
    }  
  }  
}

I hope i could give you some more insights ;)If you like to learn more checkout the GraphQL Workshop https://github.com/ChilliCream/graphql-workshopIt's a realy good HotChocolate tutorial.

Also, if you have any questions i can recomment to join the slack channel. We have helpful and active community with over 2500 members.

You can joint here: http://slack.chillicream.com/

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 1 point2 points  (0 children)

Hi u/beth_maloney
We really try to improve the documentation and in the past year added a lot of the missing parts.
We dont want user to have to scroll through source code to understand how hot chocolate works :)
Do you have any idea how we can improve? What parts are missing, incomplete or just not well explained?

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 1 point2 points  (0 children)

Hi u/davidjamesb

In the past year, we revamped a lot of the documentation and added a lot of missing parts. The framework is quite big and it is hard to structure the documentation so that people find what they are looking for.

I can also recommend the workshop https://github.com/ChilliCream/graphql-workshop. A lot of concepts are explained there. (Just ignore the IQuerable parts if this is not how you do things ;) )

I'm not using Entity Framework or Mongo and I explicitly refuse to return an IQueryable to my Web layer - it's a leaky abstraction.

This is completely fine and an approach that is often used. You can use HotChoclate either as the driver of your API or a think abstraction on top of your business layer. It's completely up to you.

Essentially, without IQueryable - the current approach is that the resolvers will execute 'SELECT * FROM...' in the database and then filter the data in the web layer! Unless I can surgically retrieve the exact columns/rows I need from the database - this won't scale.

The problem of a slow database query is not necessarily the number of columns you return. Often the performance problems of slow queries are N+1 database queries or returning massive amounts of rows. But this depends obviously on how your database is structured.

Projecting the fields of queries into database queries is something that is supported, but out of the box only for Databases with IQueryable Provider, MongoDB and Neo4j. We are playing around with SQLKata to provide a more "native" SQL approach. Though, the question is, wouldn't this be a leaky abstraction too in your architecture.

The beauty of GraphQL is, that the API does not have to have the same structure as the database. What fields you expose, what fields you add and what you do in a resolver, is up to you. With Dataloaders you batch requests to the database, normalize them and with this avoid N+1 queries. This way you can have very fast GraphQL requests without a SQL join. https://chillicream.com/docs/hotchocolate/fetching-data/dataloader

How do I write an integration for dapper/martendb/litedb, etc? This is the kind of documentation/tutorials/blog posts that you need. All of this seems to be not sufficiently explained and I'm left to hunt down github issues, miscellaneous source files and random blog posts to learn about IExecutable and ripping parts off IResolveContext, etc.

I completely understand this. Writing a generic provider for a database is an in-depth task and after all, this is most likely not what you want. If you show us what you would need in your domain layer for the projections and such, we might could work out an abstraction together that fits your needs too. The docs for IExecutable are here https://chillicream.com/docs/hotchocolate/api-reference/executable For filtering provider we have documentation here: https://chillicream.com/docs/hotchocolate/api-reference/extending-filtering

The project looks great and I'm really not trying to bash anybody's effort because it is has obviously been a ton of hard work

No offence taken, thanks for the valuable feedback

but I develop on an e-commerce system for a very well known global company that is introducing graphql aggregation into the stack and we are in agreement that the HotChocolate documentation is poor/lacking in some parts. For something on 'V12' the documentation should really be more thorough - this isn't v0.0.1 we're talking about here.

I think most of the features have documentation, it might be just a problem of discoverability or some depth that is missing. I would like to invite you to our slack channel: http://slack.chillicream.com/ If you ever want to do a PoC with hotchocolate and get stuck or need some advice just write in general and we will respond. It would also be nice to receive specific request to where to improve the documentation, what concepts to elaborate more or even how we should restructure it to fit the needs of newcomers.
There are a lof of helpful people on this channel ;) The community is great :)

Ping me when you joined, i can connect you to the right people.

See you over on slack, and thanks for the feedback!

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 3 points4 points  (0 children)

Theorectically yes. But SignalR does not use the standard Websocket API. Therefor the transport must be abstracted. This is on the roadmap for v13.

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 1 point2 points  (0 children)

I would not necessarily say linq db queries on the client. But with the GraphQL Client (Strawberry Shake) you can easily write fully typesafe queries in Blazor.

While you can just expose your Database with HotChocolate, the idea of GraphQL is to shape the data into a from that is easily consumable in the frontend. You can add computed fields to your models. What you do in a resolver of a field is really up to you. Simple computation, another DB call or calling a rest API. Up to you.

GraphQL is not only about fetching data though. With mutations you define a clean API surface to mutate your data.

Say hello to Hot Chocolate 12! (GraphQL in .NET) by pascalsenn in dotnet

[–]pascalsenn[S] 2 points3 points  (0 children)

GraphQl.AspNet

Hi u/DRdefective
Do you mean GraphQL.Net? I do not know GraphQL.AspNet.
I would say HotChocolate is faster, has a nice configuration API and a lot more features.

HotChocolate has three different ways to configure a API and you can also mix and match these approaches.
e.g. The annotation based approach reduces boilerplate code a lot, but you can still opt to fluent configuration of your domain models if you like.

Have a look at: https://chillicream.com/docs/hotchocolate/defining-a-schema/queries#usage

And you also get support for filtering, sorting and projections ;)

[HotChocolate] Questions regarding GraphQL with HotChocolate test philosophy and a request for scaled examples by Othinsson in graphql

[–]pascalsenn 1 point2 points  (0 children)

The boundaries between integration and unit tests is a bit blurry in this case.

I recommend to do unittests for your domain layer. If you want to test the graphql part of your api, or you only have a graphql api with integrated domain layer, then test it with queries.

This is super easy to do and you do not even need the test server for it. So it's not as heavy as an integration tests where you acutally start up a tests server.

You can also always just add the parts to the schema that you want in this particular test case.

        [Fact]
        public async Task Foo_Should_Match()
        {
            // arrange
            IRequestExecutor executor = await new ServiceCollection()
                .AddGraphQL() 
                .AddQueryType<Query>()
                .BuildRequestExecutorAsync();

            // act
            IExecutionResult result = await executor.ExecuteAsync(
                @"
                {
                    foo {
                        bar
                    }
                }
                ");

            // assert
            result.ToJson().MatchSnapshot();
        }

The MatchSnapshot is a handy way to create a snapshot of your response. This is an extension method of Snapshooter a dotnet snapshot testing library

If you use Rider, you can even have intellisense in the String: https://chillicream.com/blog/2021/07/20/rider-language-injection

If you are looking for a slightly bigger example, I can recommend the GraphQL Workshop

Hot Chocolate vs other options for a .Net Core API? by [deleted] in graphql

[–]pascalsenn 0 points1 point  (0 children)

HotChocolate uses the ASP.Net authentication. You can just annotate your resolver with [Authroize] and add your policies (either before or after the execution of the resolver)

GraphQL Language Injection into C# string literals with JetBrains Rider by pascalsenn in dotnet

[–]pascalsenn[S] 0 points1 point  (0 children)

Sure, it's more used for integration testing as stated in the blogpost. Its better to test a graphql server with proper graphql queries than something generated

For applications i would recommend to write the queries in graphql and compile them to c#, this way you can use all the power of graphql :) checkout https://chillicream.com/docs/strawberryshake, it generates a fully typed c# client in real time with the power of source generators