I'm always excited to take on new projects and collaborate with innovative minds.

Social Links

Building a Modern GraphQL API with .NET 8 and Hot Chocolate

Learn how to build a modern, scalable GraphQL API with .NET 8 and Hot Chocolate. This POC demonstrates querying, mutations, filtering, sorting, and cursor-based pagination with EF Core InMemory β€” a clean foundation for production-ready APIs.

πŸ” Overview

This proof of concept (POC) demonstrates how to build a modern GraphQL API on .NET 8, powered by Hot Chocolate and Entity Framework Core.
It covers querying, mutations, filtering, sorting, projections, and cursor-based pagination β€” all backed by an EF Core InMemory provider for fast iteration and testing.


πŸ’‘ Why GraphQL?

GraphQL is more than a trend β€” it’s a paradigm shift in how clients interact with APIs.

  • Single flexible endpoint β€” clients query exactly what they need, nothing more.
  • Strongly-typed schema β€” discoverable documentation and auto-completion via the built-in GraphQL IDE.
  • Efficient data access β€” server-side filtering, sorting, and pagination reduce over-fetching.
  • Production readiness β€” support for batching, caching, and resilient error handling.

βš™οΈ Tech Stack

LayerTechnologyPurpose
BackendASP.NET Core (net8.0)Hosting, middleware, dependency injection
GraphQL EngineHot ChocolateSchema, resolvers, projections, filtering, sorting
DatabaseEF Core InMemoryLightweight data storage for development
REST SupportSwashbuckle (Swagger)Legacy REST endpoint for comparison

🧱 Project Layout

FilePurpose
GraphQL\Query.csExposes GraphQL query resolvers
GraphQL\Mutation.csDefines mutations (writes)
Data\AppDbContext.csEF Core configuration
Models\Author.cs, Models\Book.csDomain entities
Program.csApplication entry point β€” wires GraphQL, EF Core, and seeds data

Key Paths

d:\Projects\GraphQLApi.POC\GraphQLApi.POC\
β”‚
β”œβ”€β”€ Program.cs
β”œβ”€β”€ GraphQL\
β”‚   β”œβ”€β”€ Query.cs
β”‚   └── Mutation.cs
└── Data\
    └── AppDbContext.cs

🧩 Data Model

public class Author {
  public int Id { get; set; }
  public string Name { get; set; } = string.Empty;
  public ICollection<Book> Books { get; set; } = new List<Book>();
}

public class Book {
  public int Id { get; set; }
  public string Title { get; set; } = string.Empty;
  public int PublishedYear { get; set; }
  public int AuthorId { get; set; }
  public Author? Author { get; set; }
}
  • One-to-many relationship β€” each Author has multiple Books.
  • Fully navigable in GraphQL queries.

⚑ GraphQL Schema

Query Type

Hot Chocolate allows seamless integration between EF Core and GraphQL by returning IQueryable<T> β€” enabling powerful server-side filtering, sorting, and projections.

public class Query
{
  [UsePaging(MaxPageSize = 50, IncludeTotalCount = true)]
  [UseProjection]
  [UseFiltering]
  [UseSorting]
  public IQueryable<Book> GetBooks([Service] AppDbContext db) => db.Books;

  [UsePaging(MaxPageSize = 50, IncludeTotalCount = true)]
  [UseProjection]
  [UseFiltering]
  [UseSorting]
  public IQueryable<Author> GetAuthors([Service] AppDbContext db) => db.Authors;
}

✏️ Mutations

A simple mutation example to create a new book:

public class Mutation
{
  public async Task<Book> AddBook(CreateBookInput input, [Service] AppDbContext db)
  {
    var book = new Book {
      Title = input.Title,
      PublishedYear = input.PublishedYear,
      AuthorId = input.AuthorId
    };

    db.Books.Add(book);
    await db.SaveChangesAsync();
    return book;
  }
}

public record CreateBookInput(string Title, int PublishedYear, int AuthorId);

πŸ”„ Pagination (Relay Style)

UsePaging provides cursor-based pagination (not offset-based), delivering both totalCount and navigational cursors.

query {
  books(first: 2) {
    totalCount
    pageInfo { hasNextPage endCursor }
    edges {
      cursor
      node {
        id
        title
        publishedYear
        author { id name }
      }
    }
  }
}

Example pagination query with a cursor:

query($cursor: String!) {
  books(first: 2, after: $cursor) {
    pageInfo { hasNextPage endCursor }
    edges { node { id title } }
  }
}

▢️ Run Locally

dotnet build
dotnet run

Endpoints

Seeded Data

AuthorBooks
Isaac AsimovFoundation (1951)
Ursula K. Le GuinThe Left Hand of Darkness (1969)

🧠 Try It Out

Query books with sorting and projection

query {
  books(order: { publishedYear: DESC }) {
    edges {
      node {
        id
        title
        publishedYear
        author { id name }
      }
    }
    totalCount
    pageInfo { hasNextPage endCursor }
  }
}

Filter authors by name

query {
  authors(where: { name: { contains: "Ursula" } }) {
    edges { node { id name books { title } } }
    totalCount
  }
}

Add a new book

mutation {
  addBook(input: { title: "The Dispossessed", publishedYear: 1974, authorId: 2 }) {
    id
    title
    author { id name }
  }
}

βš™οΈ Performance & Scalability

  • Efficient pagination β†’ limits via MaxPageSize.
  • DataLoader integration β†’ batch async lookups and eliminate N+1 queries.
  • Projection middleware β†’ reduces data transfer by selecting only queried fields.
  • Caching & schema precompilation β†’ optimize cold starts and hot-path performance.

πŸ—οΈ Production-Ready Enhancements

AreaEnhancementDescription
DatabaseSwitch to SQLite or SQL ServerReplace UseInMemoryDatabase with UseSqlite or UseSqlServer
AuthAdd authentication & authorizationUse AddAuthorization(), decorate resolvers with [Authorize]
ObservabilityAdd logging & tracingIntegrate with OpenTelemetry for distributed tracing
ValidationInput validationIntegrate FluentValidation or HotChocolate input validators
Error HandlingCustom error filtersConsistent error payloads for API consumers
TestingIntegration & resolver testsUse HttpClient and test GraphQL endpoints directly

🧩 Next Steps

To go beyond this POC:

  • Swap the InMemory provider for SQLite with EF Core migrations.
  • Introduce a DataLoader for batched author-book lookups.
  • Add auth and observability layers to make it production-ready.

🧭 Conclusion

This POC shows how easy it is to build a modern, maintainable GraphQL API using .NET 8 and Hot Chocolate.
With minimal configuration, you get a type-safe, self-documenting, high-performance API that scales gracefully.

The built-in GraphQL IDE makes exploration effortless β€” run queries, test mutations, and extend your schema with confidence.

⚑ With just a few enhancements, this POC can evolve into a fully production-grade service.

4 min read
Oct 26, 2025
By Dheer Gupta
Share

Leave a comment

Your email address will not be published. Required fields are marked *