Use Hot Chocolate and NET 6 to build GraphQL application -- realizing the basic function of Query

Posted by shonuff on Wed, 26 Jan 2022 23:54:51 +0100

Series navigation

Use Hot Chocolate and NET 6 to build GraphQL application article index

demand

In this article, we will take a simple example to see how to implement the simplest GraphQL interface.

realization

Introduce Hot Chocolate dependency package

Since I intend to put the relevant logic of GraphQL into the Applicaiton layer and use it in the Application and Api projects, the following dependency packages are introduced into the project

# Hot Chocolate is here NET Web application
HotChocolate.AspNetCore
# Hot Chocolate integrates the Nuget package of the underlying ORM framework of the EntityFramework Core
HotChocolate.Data.EntityFramework
# Some attribute definition extensions of Hot Chocolate
HotChocolate.Data
# A visual GraphQL Schema Middleware
GraphQL.Server.Ui.Voyager

Add Resolver

Add a folder GraphQL in the Api project to store the definitions related to GraphQL interface, and create a new query CS file, we define an interface here:

  • Query.cs
namespace PostGraphi.Api.GraphQL;

public class Query
{
    // [Service] is a property provided by Hot Chocolate to obtain dependency injection objects
    public IQueryable<Post> GetPosts([Service] IRepository<Post> repository) => repository.GetAsQueryable();
}

Need to be in globalusings CS add the following namespace:

  • GlobalUsings.cs
global using HotChocolate;
global using PostGraphi.Domain.Post.Entities;

Add dependency injection

  1. Add GraphQL services:
builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>();
  1. Add GraphQL endpoint configuration and Voyager Middleware
app.UseHttpsRedirection();

// Add GraphQL endpoint configuration
app.UseRouting().UseEndpoints(endpoints =>
{
    endpoints.MapGraphQL();
});

// Add Voyager middleware and configure URL
app.UseGraphQLVoyager(new VoyagerOptions { GraphQLEndPoint = "/graphql" }, "/graphql-voyager");

app.UseAuthentication();
app.UseAuthorization();

verification

To run the Api project, we first visit the address: https://localhost:7194/graphql-voyager View the home page of Voyager:

We can see that we only have one schema named posts at present. The diagram composed of the entities associated with the interface and other entities associated with the entity is very clearly displayed. In this figure, we can see that DomainEvents are also displayed, but this is not what we want. We will solve this problem later.

Check out the Banana Cake Pop homepage launched with the program officially provided by Hot Chocolate: https://localhost:7194/graphql/

On this page, we can view the specific Schema Definition and all the type definitions maintained by GraphQL Server. You can also initiate a GraphQL request directly from the Operations tab.

query {
  posts {
    id,
    title,
    author,
    comments {
      content
    }
    tags {
      name
    }
  }
}

If you use the API Client to initiate a GraphQL request, note that the request is POST https://localhost:7194/graphql , the Body content is GraphQL Query, like this:

After executing the request, let's take a look at the EFCore log output of the console:

SELECT "p"."Id", "p"."Abstraction", "p"."Author", "p"."Content", "p"."Created", "p"."CreatedBy", "p"."LastModified", "p"."LastModifiedBy", "p"."Link", "p"."PublishedAt", "p"."Title"
FROM "Posts" AS "p"

Sharp friends may find that there are no Join operations related to Comments and Tags in this sql. The following request response through Banana Cake Pop can also explain this problem:

In this return result, we can see at least two types of problems: first, the one to many and many to many associated table data of Comments and Tags are not returned at the same time; Second, the return does not seem to be sorted. We will solve these two problems one by one in the following articles.

Anyway, our first GraphQL interface has been called successfully. Let's solve the problem of DomainEvents mentioned above.

improvement

Because we use the Annotation First method to build the interface by default, and we use the entity object directly without any configuration, because I don't want to directly configure the business-related interface attributes to my Domain Model. At this time, we need to use the Code First method to define the corresponding GraphQL class for the Post class.

Create a new folder Types in Api/GraphQL and create posttype CS, let it inherit from the objectType < T > type provided by Hot Chocolate, and override the Configure method:

  • PostType.cs
namespace PostGraphi.Api.GraphQL.Types;

public class PostType : ObjectType<Post>
{
    protected override void Configure(IObjectTypeDescriptor<Post> descriptor)
    {
        descriptor.Description("Represents Post Entity Type.");
        // Ignore this field when building the schema
        descriptor.Field(d => d.DomainEvents).Ignore();
    }
}

Need to be in globalusings Introduction of namespace in CS:

  • GlobalUsings.cs
global using HotChocolate.Types;

Finally, add the Type at the place of dependency injection:

builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddType<PostType>();

Run the program again. We check on the Voyager home page. DomainEvents has disappeared:

summary

In this paper, we implement the simplest GraphQL interface, and use the two methods provided by Hot Chocolate to realize the function of Annotation First and Code First. In fact, there is another important concept about Code First method called Resolver, which we did not cover in the article demonstration. This concept can be understood as that when defining GraphQL objects through Code First method, we can use ResolveWith to specify what Resolver to use to obtain data. For more configuration methods, please refer to the official documents: Resolvers.

In this paper, we also leave two questions. The next article will realize the acquisition method of associated entity objects.

Reference articles

  1. Resolvers

Topics: graphql