Generate Type‑Safe GraphQL Clients in .NET 8 with Strawberry Shake Source Generators

Mahmut Sarıkaya 5 dk okuma 12 Görüntülenme 0
Generate Type‑Safe GraphQL Clients in .NET 8 with Strawberry Shake Source Generators

Why type‑safe GraphQL matters in modern .NET apps

Imagine a production service that crashes because a GraphQL field was renamed but the client code still expects the old name. In .NET 8 the cost of such mismatches is amplified by strong typing and high‑performance expectations. A type‑safe GraphQL client eliminates runtime surprises by generating C# models that mirror the schema exactly, letting the compiler catch errors before deployment.

Introducing Strawberry Shake and source generators

Strawberry Shake, part of the HotChocolate ecosystem, leverages .NET 8 source generators to produce compile‑time client code from a GraphQL schema. Unlike manual HttpClient wrappers, the generated client respects nullable reference types, async streams, and dependency injection out of the box. The approach follows the same pattern as Entity Framework Core’s DbContext generation, but for GraphQL operations.

System requirements and project setup

Before you begin, ensure you have .NET SDK 8.0.100 or later and a recent version of Visual Studio 2022 (or VS Code with C# extension). Open a terminal and create a fresh console project:

dotnet new console -n GraphQLDemo

Navigate into the folder and add the Strawberry Shake packages:

cd GraphQLDemo
dotnet add package StrawberryShake\Client
dotnet add package StrawberryShake\CodeGeneration.CSharp

These packages contain the source generator and the runtime client library.

Defining the GraphQL schema source

Create a folder named GraphQL and place a schema.graphql file that matches the endpoint you intend to call. For illustration, we use the public SpaceX API schema snippet:

type Query { launchesPast(limit: Int): [Launch] }

Next, add a launches.graphql file that defines the operation you need:

query GetPastLaunches($limit: Int) { launchesPast(limit: $limit) { mission_name launch_date_utc } }

Notice the exact field names – the generator will translate them into C# properties with matching casing.

Configuring Strawberry Shake with a .csproj entry

Open GraphQLDemo.csproj and insert a StrawberryShake ItemGroup. This tells the source generator where to find schema and operation files, and which endpoint to target.

<ItemGroup> <PackageReference Include="StrawberryShake.Client" Version="12.0.0" /> <PackageReference Include="StrawberryShake.CodeGeneration.CSharp" Version="12.0.0" /> </ItemGroup> <ItemGroup> <GraphQLFile Include="GraphQL\*.graphql" /> </ItemGroup> <PropertyGroup> <StrawberryShake_GraphQLEndpoint>https://api.spacex.land/graphql/</StrawberryShake_GraphQLEndpoint> <StrawberryShake_GenerateClient>true</StrawberryShake_GenerateClient> </PropertyGroup>

After saving, run dotnet build. The generator creates a IGraphQLClient interface, a concrete GraphQLClient class, and strongly typed request/response models inside the Generated namespace.

Using the generated client in code

Inject the client via the built‑in DI container. Update Program.cs as follows:

using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using MyProject.Generated; var host = Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { services.AddStrawberryShakeClient(); }) .Build(); var client = host.Services.GetRequiredService<IGraphQLClient>(); var result = await client.GetPastLaunches.ExecuteAsync(new GetPastLaunchesRequest(5)); if (result.Data?.LaunchesPast != null) { foreach (var launch in result.Data.LaunchesPast) { Console.WriteLine($"Mission: {launch.MissionName}, Date: {launch.LaunchDateUtc:u}"); } } else { Console.WriteLine("No data returned or errors occurred."); } await host.RunAsync();

The GetPastLaunchesRequest type is generated from the query definition, guaranteeing that the limit argument is an int and that the response properties match the schema exactly. Any mismatch would be flagged by the compiler.

Advanced configuration: batching and caching

Strawberry Shake supports request batching out of the box. To enable it, add the following to the appsettings.json file:

{ "StrawberryShake": { "Batching": { "Enabled": true, "BatchSize": 10, "BatchIntervalMs": 50 } } }

When multiple queries are dispatched within the configured interval, the runtime bundles them into a single HTTP POST, reducing network overhead. For caching, register an in‑memory cache service and configure the client:

services.AddMemoryCache(); services.AddStrawberryShakeClient(options => { options.UseMemoryCache = true; options.CacheTTL = TimeSpan.FromMinutes(5); });

These settings are especially useful in high‑traffic microservices where latency budgets are measured in milliseconds.

Testing the generated client

Because the client is an interface, you can mock it with any standard .NET mocking library. For example, using Moq:

var mock = new Mock<IGraphQLClient>(); mock.Setup(c => c.GetPastLaunches.ExecuteAsync(It.IsAny<GetPastLaunchesRequest>())) .ReturnsAsync(new GraphQLResult<GetPastLaunchesResult>(new GetPastLaunchesResult { LaunchesPast = new[] { new Launch { MissionName = "Demo", LaunchDateUtc = DateTime.UtcNow } } }));

This approach lets you verify business logic without contacting the remote GraphQL server, reinforcing the type‑safe contract throughout your test suite.

Performance considerations in .NET 8

Source generators run at compile time, so there is zero runtime reflection overhead. Benchmarks from the official HotChocolate repo show a 30 % reduction in latency compared to a hand‑crafted HttpClient wrapper when executing 1,000 concurrent queries. .NET 8’s native AOT compilation can further shrink the binary size of the generated client, making it suitable for edge deployments.

Common pitfalls and how to avoid them

1. **Schema drift** – If the remote schema changes, rebuild the solution. The generator will surface missing fields as compile‑time errors. 2. **Nullable reference types** – Ensure your project enables nullable context; otherwise the generated models will default to non‑nullable, potentially hiding null‑ability information. 3. **Multiple endpoints** – Strawberry Shake supports only one endpoint per project. For multi‑service architectures, create separate class library projects for each GraphQL service.

Conclusion

By coupling .NET 8 source generators with Strawberry Shake, developers obtain a fully type‑safe GraphQL client that integrates seamlessly with dependency injection, async streams, and modern performance features. The compile‑time guarantees reduce runtime bugs, improve developer productivity, and align perfectly with the strong‑typing philosophy of C#. Adopt the steps outlined above, and your next .NET service will query GraphQL APIs with confidence and speed.

Sources

HotChocolate official documentation, Strawberry Shake GitHub repository, Microsoft .NET 8 release notes

Author: Mahmut Sarıkaya — sarikayadev.com

Etiketler: #dotnet 8 #graphql client #strawberry shake #source generators #type‑safe
Paylaş:
M

Yazar

Mahmut Sarıkaya

yazılım Geliştirici

Yorumlar

Henüz yorum yok. İlk yorumu siz yapın!

Yorum Bırakın

6 + 2 =