Building a GraphQL API with HotChocolate - Part 4

In this final post, we explore the implementation of a GraphQL server in C# and demonstrate how it can be queried from an HTML file using JavaScript.

Information

The code for this section is publicly available for download on GitHub. Access it by visiting the following repository: EOCS.GraphQL.

As previously mentioned, GraphQL is a specification that can be effectively implemented in various languages. Here, we will explore one such implementation written in C#.

What is HotChocolate ?

HotChocolate is an open-source GraphQL server for the Microsoft .NET platform that is compliant with the newest GraphQL October 2021 spec + Drafts, which makes Hot Chocolate compatible to all GraphQL compliant clients.
https://chillicream.com/docs/hotchocolate/v13

We'll set up a basic GraphQL server using HotChocolate in an Azure Function, and then we'll query it with JavaScript.

Creating the environment

  • Create a new solution named EOCS.GraphQL for example and a new Azure Functions project in it.

  • Create a new class named Customer.cs and add the following code to it.

1public class Customer
2{
3    public string Id { get; set; }
4
5    public string Name { get; set; }
6
7    public int Age { get; set; }
8}
  • Create a new interface named ICustomerRepository and add the following code in it.
1public interface ICustomerRepository
2{
3    List<Customer> GetAllCustomers();
4}
  • Create a new class named MockCustomerRepository that implements the ICustomerRepository interface.
 1public class MockCustomerRepository : ICustomerRepository
 2{
 3    public List<Customer> GetAllCustomers()
 4    {
 5        return new List<Customer>()
 6        {
 7            new Customer(){ Id = "0001", Name = "Bruce Smith", Age = 45 },
 8            new Customer(){ Id = "0010", Name = "Melissa Price", Age = 52 }
 9        };
10    }
11}
Information

So far, there's nothing particularly groundbreaking: we're about to create a GET endpoint that returns data about customers.

Using HotChocolate

  • Add the HotChocolate.AzureFunctions NuGet package.

  • Add a class named Query.cs with the following code.

1public class Query
2{
3    public List<Customer> GetCustomers([Service] ICustomerRepository customerRepository)
4    {
5        return customerRepository.GetAllCustomers();
6    }
7}

Here is where we start setting up the GraphQL server by defining the ability to query customers. HotChocolate will handle all the necessary infrastructure, allowing us to query only the data we need.

All that's left for us to do is to provide the single entry point.

  • Create a class named CustomerService.cs (or a more general name) and add the following code to it.
 1public class CustomerService
 2{
 3    private readonly IGraphQLRequestExecutor _executor;
 4
 5    public CustomerService(IGraphQLRequestExecutor executor)
 6    {
 7        _executor = executor;
 8    }
 9
10    [FunctionName(nameof(Run))]
11    public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "graphql/{**slug}")] HttpRequest req)
12    {
13        return await _executor.ExecuteAsync(req);
14    }
15}
Information

We can witness the significant advantages of GraphQL in action: we only need one endpoint to handle all the requests.

  • Create a class named StartUp.cs to bootstrap the Azure Function.
 1public class StartUp : FunctionsStartup
 2{
 3    public override void Configure(IFunctionsHostBuilder builder)
 4    {
 5        ConfigureServices(builder.Services);
 6    }
 7
 8    private static void ConfigureServices(IServiceCollection services)
 9    {
10        services.AddSingleton<ICustomerRepository, MockCustomerRepository>();
11
12        services.AddGraphQLFunction().AddQueryType<Query>();
13    }
14}

Here, we specify that we intend to add GraphQL features. Once again, this setup is facilitated by HotChocolate.

Consuming the service

Now it's time to consume our service, and for this, we will create a simple HTML file.

  • Create a new ASP.NET Core project and add a file named index.html in wwwroot.

  • Add the following code to it.

 1<html>
 2<head>
 3    <title>GraphQL</title>
 4</head>
 5<body>
 6    <pre><code class="language-json" id="code"></code></pre>
 7    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.min.js"></script>
 8    <script>
 9        (async function () {
10            const data = JSON.stringify({
11                query: `query {
12                  customers {
13                    id                    
14                    age
15                  }
16                }`
17            });
18
19            const response = await fetch(
20                'http://localhost:7020/api/graphql',
21                {
22                    method: 'post',
23                    body: data,
24                    headers: {
25                        'Content-Type': 'application/json'
26                    },
27                }
28            );
29
30            const json = await response.json();
31            document.getElementById('code').innerHTML = js_beautify(
32                JSON.stringify(json.data)
33            );
34        })();
35    </script>
36</body>
37</html>
  • Edit the Program.cs code.
 1public class Program
 2{
 3    public static void Main(string[] args)
 4    {
 5        var builder = WebApplication.CreateBuilder(args);
 6        var app = builder.Build();
 7        
 8        app.UseDefaultFiles();
 9        
10        app.UseStaticFiles();
11        
12        app.Run(async (context) =>
13        {
14            await context.Response.WriteAsync("Request Handled and Response Generated");
15        });
16        
17        app.Run();
18    }
19}
Information

Here, we can observe how we structure the data to retrieve what we need: we simply specify that we are interested in the customers' id and age, and then post it to the /graphql endpoint.

Running the program

Here is the result obtained when the applications are executed.

Now, suppose we are also interested in the name. It's simple: the client just needs to modify its request.

 1<html>
 2<head>
 3    <title>GraphQL</title>
 4</head>
 5<body>
 6    <pre><code class="language-json" id="code"></code></pre>
 7    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.min.js"></script>
 8    <script>
 9        (async function () {
10            const data = JSON.stringify({
11                query: `query {
12                  customers {
13                    id 
14				    name
15                    age
16                  }
17                }`
18            });
19
20            const response = await fetch(
21                'http://localhost:7020/api/graphql',
22                {
23                    method: 'post',
24                    body: data,
25                    headers: {
26                        'Content-Type': 'application/json'
27                    },
28                }
29            );
30
31            const json = await response.json();
32            document.getElementById('code').innerHTML = js_beautify(
33                JSON.stringify(json.data)
34            );
35        })();
36    </script>
37</body>
38</html>

We can observe that we can now retrieve only the desired data without the necessity to redeploy additional endpoints.

Final thoughts

If you wish to delve deeper into this topic, acquire the following books, which encompass all the concepts emphasized in this series and delve into more advanced ones.

Learning GraphQL: Declarative Data Fetching for Modern Web Apps (Porcello, Banks)

Apps and Services with .NET 8: Build practical projects with Blazor, .NET MAUI, gRPC, GraphQL, and other enterprise technologies (Price)

Do not hesitate to contact me shoud you require further information.