Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Build an ASP.NET Core API using StrawberryShake (recommended)

Learn how to build an ASP.NET Core Web API that retrieves content from Optimizely Graph using StrawberryShake for strongly typed queries and automatic client generation.

This guide shows how to build an ASP.NET Core Web API that connects to Optimizely Graph using StrawberryShake, a strongly typed GraphQL client with automatic code generation. Use this approach when you want compile-time query validation and generated models that keep the C# code in sync with the Optimizely Graph schema.

Optimizely recommends this approach for most production applications because StrawberryShake does the following:

  • Validates queries at build time.
  • Generates strongly typed models automatically.
  • Provides IntelliSense support.
  • Reduces manual serialization and mapping code.

For a lightweight manual client instead, see Build an ASP.NET Core API (manual GraphQL client).

Create an ASP.NET Core project

Scaffold the Web API project that hosts the StrawberryShake-generated client and the controllers in the rest of the guide.

dotnet new webapi -n MyOptimizelyApp
cd MyOptimizelyApp

Install StrawberryShake tools

Add the StrawberryShake CLI tools to the local manifest so the project can download schemas and generate the typed client.

dotnet new tool-manifest
dotnet tool install StrawberryShake.Tools

Install StrawberryShake packages

Add the runtime and code-generation packages that the generated client depends on.

dotnet add package StrawberryShake.AspNetCore
dotnet add package StrawberryShake.CodeGeneration.CSharp.Analyzers

Configure the project

Register .graphql files as inputs to the source generator so StrawberryShake picks up the query documents during build.

Update MyOptimizelyApp.csproj.

<ItemGroup>
  <GraphQL Include="**/*.graphql" />
</ItemGroup>

Download the schema

Pull the Optimizely Graph schema into the project so StrawberryShake validates queries against the live shape of the service.

dotnet graphql download https://cg.optimizely.com/content/v2?auth=YOUR_KEY -f schema.graphql

Create GraphQL queries

Define the queries StrawberryShake compiles into strongly typed methods on the generated client.

Create Queries/ArticleQueries.graphql.

query GetArticles($limit: Int = 10, $skip: Int = 0) {
  ArticlePage(orderBy: { _modified: DESC }, limit: $limit, skip: $skip) {
    items {
      ContentLink { Id }
      Name
      RelativePath
      TeaserText
      PageImage { Url }
      MainBody
    }
    total
  }
}

query GetArticleById($id: String!) {
  ArticlePage(where: { ContentLink: { Id: { eq: $id } } }) {
    items {
      ContentLink { Id }
      Name
      RelativePath
      TeaserText
      PageImage { Url }
      MainBody
      _modified
    }
  }
}

Configure StrawberryShake

Point StrawberryShake at the downloaded schema and the query folder, and name the generated client and namespace.

Create .graphqlrc.json.

{
  "schema": "schema.graphql",
  "documents": "Queries/**/*.graphql",
  "extensions": {
    "strawberryShake": {
      "name": "OptimizelyGraphClient",
      "namespace": "MyOptimizelyApp.GraphQL",
      "url": "https://cg.optimizely.com/content/v2?auth=YOUR_KEY"
    }
  }
}

Register the generated client

Wire the StrawberryShake client into dependency injection so controllers receive IOptimizelyGraphClient through the constructor.

Update Program.cs.

using MyOptimizelyApp.GraphQL;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddOptimizelyGraphClient()
    .ConfigureHttpClient(client =>
    {
        client.BaseAddress =
            new Uri("https://cg.optimizely.com/content/v2?auth=YOUR_KEY");
    });

builder.Services.AddControllers();

var app = builder.Build();

app.UseRouting();
app.MapControllers();
app.Run();

Generate the client

Run dotnet build to generate strongly typed classes in MyOptimizelyApp.GraphQL.

Create a controller

Expose the generated GraphQL operations through REST endpoints that the front end consumes.

using Microsoft.AspNetCore.Mvc;
using MyOptimizelyApp.GraphQL;

[ApiController]
[Route("api/[controller]")]
public class ArticlesController : ControllerBase
{
    private readonly IOptimizelyGraphClient _graphQLClient;

    public ArticlesController(IOptimizelyGraphClient graphQLClient)
    {
        _graphQLClient = graphQLClient;
    }

    [HttpGet]
    public async Task<ActionResult> GetArticles(int limit = 10, int skip = 0)
    {
        var result = await _graphQLClient.GetArticles.ExecuteAsync(limit, skip);

        if (result.IsErrorResult())
        {
            return BadRequest(result.Errors);
        }

        return Ok(result.Data?.ArticlePage);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult> GetArticleById(string id)
    {
        var result = await _graphQLClient.GetArticleById.ExecuteAsync(id);

        if (result.IsErrorResult())
        {
            return BadRequest(result.Errors);
        }

        var article = result.Data?.ArticlePage?.Items?.FirstOrDefault();

        if (article == null)
        {
            return NotFound();
        }

        return Ok(article);
    }
}

Run and test

Build and run the API to confirm the generated client resolves correctly and the endpoints return content from Optimizely Graph.

dotnet build
dotnet run

Open the following endpoints in a browser or API tool.

  • https://localhost:7000/api/articles – Retrieves all articles from Optimizely Graph.
  • https://localhost:7000/api/articles/{ID} – Retrieves a specific article by its content ID. Replace {ID} with an actual article ID.