In this article, we’ll get familiar with GraphQL and Strawberry Shake, a GraphQL tool that facilitates interaction with local and remote data.

Subsequently, we will build an application using the .NET API, focusing on customers searching for available space in shipping containers using GraphQL. This article will not delve deeply into server-side implementation since we have learned about it in one of our previous articles.

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Introduction to Strawberry Shake

The Strawberry Shake client tool uses the GraphQL query and manipulation language and supports the latest GraphQL draft spec-compliant features, which makes it compatible with a broad array of GraphQL servers, including Hot Chocolate, Apollo Server, GraphQL Java, and others.

Strawberry Shake is primarily used for generating .NET clients for GraphQL, essentially for mobile apps that fetch data from social media applications via a strongly typed client. Moreover, it facilitates interactions with both local and remote data sources, such as managing data from a local cache or retrieving remote product details from an e-commerce platform’s GraphQL API. Additionally, it integrates with .NET’s reactive API for state communication, ideal for real-time UI updates in applications like trading system dashboards that stream financial stock data through GraphQL subscriptions.

Project Setup With Strawberry Shake CLI Tool

Firstly, let’s create a new file called tool-manifest to keep all necessary project tools:

dotnet new tool-manifest

This file pairs with the dotnet tool install command. When we install a tool with this command and a tool manifest file is present, the tool gets added to the manifest, thus making it callable from anywhere within the directory hierarchy of the manifest file.

This strategy ensures that specific tool versions stay linked with the project, promoting consistency across all contributors.

Now, let’s install the Strawberry Shake tool:

dotnet tool install StrawberryShake.Tools --local

Here, the dotnet tool install command integrates Strawberry Shake tools into the local manifest, making them callable from the project repository.

Create ASP.NET Core Web API Server Project

To consume data, our GraphQL client will interact with a server providing data on available shipping container space.

The goal of this article is to introduce Strawberry Shake, so we are not going to dive deep into the GraphQL server implementation part. For those interested, a detailed explanation is available in our previous articles.

To start, we’ll create a new project using the dotnet new web command.

Next, let’s add a new class ShippingContainer to our server project:

public class ShippingContainer
{
    public string? Id { get; set; }
    [Required]
    [StringLength(100)]
    public string? Name { get; set; }
    public AvailableSpace? Space { get; set; }

    public class AvailableSpace
    {
        [Required]
        public double Length { get; set; }
        [Required]
        public double Width { get; set; }
        [Required]
        public double Height { get; set; }

        public double Volume => Length * Width * Height;
    }
}

The next step is to add the EntityFramework NuGet package for the SQLite database:

dotnet add .\GraphQLStrawberryShake.Server\ package Microsoft.EntityFrameworkCore.Sqlite

Now that we have the necessary package, we can create a DbContext for the database:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<ShippingContainer> ShippingContainers { get; set; } = default!;

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ShippingContainer>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Name).IsRequired().HasMaxLength(100);
            entity.OwnsOne(e => e.Space, space =>
            {
                space.Property(e => e.Length).IsRequired();
                space.Property(e => e.Width).IsRequired();
                space.Property(e => e.Height).IsRequired();
            });
        });
    }
}

Next, let’s set up GraphQL for our server project.

Add GraphQL Server to Web API Server Project

Firstly, we need to add HotChocolate as the GraphQL server for handling GraphQL requests:

dotnet add GraphQLStrawberryShake.Server package HotChocolate.AspNetCore

Here, we integrate HotChocolate, a popular .NET GraphQL server framework, into our server project, enabling us to construct and serve GraphQL endpoints effectively.

For querying available shipping containers, it’s important to define a query type that can fetch data from our database:

public class Query
{
    public IEnumerable<ShippingContainer> GetShippingContainers([Service] ApplicationDbContext dbContext) =>
        dbContext.ShippingContainers;
}

Here, we define a Query class with a method GetShippingContainers() that retrieves shipping container records from the database. The [Service] attribute injects the ApplicationDbContext, which makes entity retrieval straightforward.

Subsequently, after defining our query type, the next step is to configure the GraphQL server and register our query type in the Program class. This involves setting up HotChocolate to recognize our Query class as the root query type:

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

We have to invoke the AddGraphQLServer() method for our GraphQL server setup. Then, with the AddQueryType<Query>() method, we can register our Query class, enabling GraphQL to understand and execute the queries we define.

Following the server configuration, we need to set up the GraphQL middleware in the Program class to handle GraphQL HTTP requests:

app.MapGraphQL();

Our middleware will intercept requests directed at the /graphql endpoint and process them using the GraphQL server we’ve set up. Consequently, it allows our API to respond to GraphQL queries.

Add Strawberry Shake GraphQL Client to Web API Project

Now that our project can transfer data via HTTP, let’s facilitate code generation and backend communication:

dotnet add .\GraphQLStrawberryShake\ package StrawberryShake.Server

Integrating a GraphQL client into our project requires ensuring that the server is running, so let’s do that with the dotnet run command.

After our server is running, we can start setting up the GraphQL client in our project:

dotnet graphql init http://localhost:5167/graphql/ -n ShippingContainerClient -p .\GraphQLStrawberryShake\

Here, we use the dotnet graphql command to generate configuration files necessary for the Strawberry Shake client to interact with our GraphQL server.

The CLI tool will generate three files to configure the client:

GraphQLStrawberryShake/.graphqlrc.json 
GraphQLStrawberryShake/schema.extensions.graphql
GraphQLStrawberryShake/schema.graphql

In the .graphqlrc.json configuration file, we set the client’s namespace, the server’s URL, and other details that adjust the client’s behavior to meet our project’s requirements:

{
  "schema": "schema.graphql",
  "documents": "**/*.graphql",
  "extensions": {
    "strawberryShake": {
      "name": "ShippingContainerClient",
      "namespace": "GraphQLStrawberryShake.GraphQL",
      "url": "http://localhost:5167/graphql/",
      "records": {
        "inputs": false,
        "entities": false
      },
      "transportProfiles": [
        {
          "default": "Http",
          "subscription": "WebSocket"
        }
      ]
    }
  }
}

Configuring the client correctly is crucial for enabling communication between our .NET application and the GraphQL server. This setup defines how queries, mutations, and subscriptions are handled, leveraging HTTP for queries/mutations and WebSocket for subscriptions.

Generate GraphQL Client Code With Strawberry Shake

With everything configured, we’re ready to execute our first query and ensure the client is correctly set up. To do this, let’s create a query that retrieves a list of available shipping containers.

We’ll start by creating a new document named GetShippingContainers.graphql:

query GetShippingContainersName {
    shippingContainers {
        name
    }
}

Next, we’ll compile the project to generate the client code:

dotnet build .\GraphQLStrawberryShake\GraphQLStrawberryShake.csproj

The generated code will be located in the ./obj/<configuration>/<target-framework>/berry directory.

Finally, we’ll register the ShippingContainerClient in the application’s dependency injection container to make it available throughout the project:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddShippingContainerClient()
    .ConfigureHttpClient(client =>
    {
        client.BaseAddress = new Uri("http://localhost:5167/graphql");
    });

var app = builder.Build();

var client = app.Services.GetRequiredService<IShippingContainerClient>();

app.Run();

Note: Sometimes, it may be necessary to reload the project to ensure that IntelliSense recognizes newly generated code correctly.

It must be remembered we have to be careful to follow these steps. As well as ensure that our .NET application is equipped with a fully functional GraphQL client, ready to communicate with the GraphQL server and perform data operations as required by the application’s logic.

Fetch Data Using GraphQL Client

Since the GraphQL client is ready, fetching data is the next step. This involves executing a GraphQL query through the client and processing the received response:

app.MapGet("/ShippingContainer", async (IShippingContainerClient client) =>
{
    var result = await client.GetShippingContainersName.ExecuteAsync();
    result.EnsureNoErrors();

    return JsonSerializer.Serialize(result.Data!.ShippingContainers);
});

Here, we define the /ShippingContainer endpoint, which takes our generated IShippingContainerClient interface. In our endpoint, we call the ExecuteAsync() method on the GetShippingContainersName query we defined earlier. Next, we check for any errors, and finally serialize the data to JSON and return it to the client.

Now, Let’s run the web application and navigate to our endpoint to retrieve our expected output:

[
    {
        "Name": "Container 1"
    },
    {
        "Name": "Container 2"
    },
    {
        "Name": "Container 3"
    },
    {
        "Name": "Container 4"
    }
]

Here, we return the list of containers, proving we successfully used Strawberry Shake to generate our GraphQL client and communicate with the server.

Conclusion

Through this article, we’ve navigated the configuration and utilization of the Strawberry Shake client. We’ve learned the installation and the addition of the Strawberry Shake client to our project, the configuration of .graphqlrc files, and the method for fetching data from a remote GraphQL server. While we haven’t explored Strawberry Shake subscriptions here, that’s a topic we plan to cover in the upcoming article.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!