---
title: Build an ASP.NET Core API (manual GraphQL client)
slug: graph/docs/build-an-asp-net-core-api-manual-graphql-client
docTags: 
createdAt: 2026-07-30T20:30:19.480Z
---

This guide shows how to build an ASP.NET Core Web API that connects to Optimizely Graph, queries content with GraphQL, and exposes the results through REST endpoints. Use the manual GraphQL client approach when you want a lightweight integration and full control over query strings and response models.

The manual client approach fits the following scenarios:

- Small or experimental projects.
- Learning how GraphQL requests and responses work.
- Projects that need full control over queries and models.

For automatic code generation, strong typing, and compile-time validation, see [Build an ASP.NET Core API with StrawberryShake](docId\:sNcLLcLYgWv_QVb0Mtqus) instead.

## Create an ASP.NET Core project

Scaffold a Web API project that hosts the controllers and GraphQL client wiring used throughout this guide.

```bash
dotnet new webapi -n MyOptimizelyApp
cd MyOptimizelyApp
```

## Install dependencies

Add the GraphQL HTTP client packages that send queries to Optimizely Graph and deserialize the JSON responses.

```bash
dotnet add package GraphQL.Client
dotnet add package GraphQL.Client.Serializer.Newtonsoft
dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions
```

## Create GraphQL schema and queries

Download the schema and author the queries the controller sends to Optimizely Graph. The examples below target the [Alloy template](docId\:sU_X-JPYqwi1Yqjdn5djC) content types.

```bash
# Download schema
dotnet graphql download https://cg.optimizely.com/content/v2?auth=YOUR_ACCESS_KEY -f schema.graphql
```

Use the following query to retrieve a list of articles from the database.

```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 the GraphQL client

Configure the GraphQL client so the controller can resolve a typed HTTP client at runtime and send queries to Optimizely Graph.

Create a `.graphqlrc.json` configuration file.

```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 GraphQL client in `Program.cs`.

```csharp
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<GraphQLHttpClient>(provider =>
{
    return new GraphQLHttpClient(
        "https://cg.optimizely.com/content/v2?auth=YOUR_KEY",
        new NewtonsoftJsonSerializer()
    );
});

builder.Services.AddControllers();

var app = builder.Build();

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

### Store the endpoint in configuration (optional)

Move the Optimizely Graph endpoint out of code into `appsettings.json` so environments override the value without recompiling.

```json
{
  "OptimizelyGraph": {
    "Endpoint": "https://cg.optimizely.com/content/v2?auth=YOUR_KEY"
  }
}
```

## Create the response model

Define C# classes that mirror the GraphQL response shape so the deserializer maps fields onto strongly typed objects.

```csharp
public class Article
{
    public ContentLink ContentLink { get; set; }
    public string Name { get; set; }
    public string RelativePath { get; set; }
    public string TeaserText { get; set; }
    public MediaReference PageImage { get; set; }
    public string MainBody { get; set; }
}

public class ContentLink { public string Id { get; set; } }

public class MediaReference { public string Url { get; set; } }

public class ContentResponse
{
    public List<Article> Items { get; set; } = new();
    public int Total { get; set; }
}

public class GraphQLResponse<T>
{
    public T ArticlePage { get; set; }
}
```

## Create a controller

Expose the Optimizely Graph data through an [ASP.NET Core controller](https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-10.0) that sends GraphQL queries with the manual client and returns the results from REST endpoints.

Create `Controllers/ArticlesController.cs`.

```csharp
using GraphQL;
using GraphQL.Client.Http;
using Microsoft.AspNetCore.Mvc;

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

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

    [HttpGet]
    public async Task<ActionResult> GetArticles()
    {
        var query = @"
        query {
            ArticlePage(orderBy: { _modified: DESC }, limit: 10) {
                items {
                    ContentLink { Id }
                    Name
                    RelativePath
                    TeaserText
                    PageImage { Url }
                    MainBody
                }
                total
            }
        }";

        var request = new GraphQLRequest { Query = query };
        var response =
            await _graphQLClient.SendQueryAsync<GraphQLResponse<ContentResponse>>(request);

        if (response.Errors?.Any() == true)
        {
            return BadRequest(response.Errors);
        }

        return Ok(response.Data.ArticlePage);
    }
}
```

## Run and test the API

Build and run the application to confirm the controller resolves the GraphQL client and returns content from Optimizely Graph.

```bash
dotnet build
dotnet run
```

### Test the API endpoint

Send a request to the controller route to verify the round trip between the API, the manual GraphQL client, and Optimizely Graph.

Use the `https://localhost:7000/api/articles` endpoint to test the API and confirm it returns content from Optimizely Graph.
