Implementing GraphQL in .NET for a Todo API

By Anubhav Kumar — Published: 12-Jan-2026 • Last updated: 13-Jan-2026 55

1. Introduction

Modern applications—especially SPAs and mobile apps—require APIs that are flexible, efficient, and scalable. Traditional REST APIs often return fixed data structures, leading to problems like over-fetching (getting more data than needed) or under-fetching (requiring multiple API calls).

GraphQL solves these problems by allowing clients to request exactly the data they need through a single endpoint, guided by a strongly typed schema.

In this article, we will build a Todo API using GraphQL in .NET, step by step, using Hot Chocolate, one of the most mature GraphQL libraries for .NET.

This guide is intentionally detailed and suitable for:

2. What is GraphQL?

GraphQL is a query language for APIs and a runtime for executing those queries using your existing data.

 

Key Characteristics

  • Single Endpoint: Typically /graphql
  • Strongly Typed Schema: Contract between client and server
  • Client-driven Queries: Client decides the shape of the response
  • Introspection: APIs are self-documenting

 

REST vs GraphQL (Quick Comparison)

Feature REST GraphQL
Endpoints Multiple Single
Over-fetching Common Eliminated
Under-fetching Common Eliminated
Versioning Required Usually not needed
Schema Implicit Explicit & Typed

3. Why Use GraphQL for a Todo API?

Although a Todo API is simple, it demonstrates real-world GraphQL benefits:

  • Query only id and title when needed
  • Fetch a single Todo or all Todos with the same endpoint
  • Combine multiple operations in one request
  • Clean evolution of API without breaking clients

4. Project Setup

4.1 Create the Project

dotnet new webapi -n TodoGraphQLApi
cd TodoGraphQLApi

Remove sample files like WeatherForecast.cs to keep the solution clean.

4.2 Install Required NuGet Packages

We will use Hot Chocolate for GraphQL support:

dotnet add package HotChocolate.AspNetCore
dotnet add package HotChocolate.Data
dotnet add package HotChocolate.Types

Why Hot Chocolate?

  • Native .NET experience
  • Schema-first and code-first support
  • Excellent performance
  • Actively maintained

5. Designing the Domain Model

5.1 Todo Entity

public class TodoItem
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public bool IsCompleted { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

This model will later map directly to GraphQL types.

6. Data Access Layer (Repository Pattern)

To keep GraphQL resolvers clean and testable, we use a repository layer.

6.1 Repository Interface

public interface ITodoRepository
{
    IEnumerable<TodoItem> GetAll();
    TodoItem? GetById(int id);
    TodoItem Add(TodoItem todo);
    TodoItem? Update(int id, bool isCompleted);
    bool Delete(int id);
}

6.2 In-Memory Repository Implementation

public class TodoRepository : ITodoRepository
{
    private readonly List<TodoItem> _todos = new();
    private int _idCounter = 1;

    public IEnumerable<TodoItem> GetAll() => _todos;

    public TodoItem? GetById(int id)
        => _todos.FirstOrDefault(t => t.Id == id);

    public TodoItem Add(TodoItem todo)
    {
        todo.Id = _idCounter++;
        _todos.Add(todo);
        return todo;
    }

    public TodoItem? Update(int id, bool isCompleted)
    {
        var todo = GetById(id);
        if (todo == null) return null;
        todo.IsCompleted = isCompleted;
        return todo;
    }

    public bool Delete(int id)
    {
        var todo = GetById(id);
        if (todo == null) return false;
        _todos.Remove(todo);
        return true;
    }
}

In real projects, this can be replaced with Entity Framework + SQL Server/PostgreSQL without changing GraphQL logic.

7. GraphQL Schema Concepts

GraphQL APIs are built around:

  • Query – Read operations
  • Mutation – Write operations
  • Type System – Object, Input, Enum, Scalar

Hot Chocolate automatically infers schema from C# classes.

8. Implementing GraphQL Queries

Queries fetch data and must be side-effect free.

public class Query
{
    public IEnumerable<TodoItem> GetTodos([Service] ITodoRepository repo)
        => repo.GetAll();

    public TodoItem? GetTodoById(int id, [Service] ITodoRepository repo)
        => repo.GetById(id);
}

Example Query

query {
  todos {
    id
    title
    isCompleted
  }
}

9. Implementing GraphQL Mutations

Mutations modify server-side data.

public class Mutation
{
    public TodoItem AddTodo(string title, [Service] ITodoRepository repo)
    {
        return repo.Add(new TodoItem
        {
            Title = title,
            IsCompleted = false
        });
    }

    public TodoItem? CompleteTodo(int id, [Service] ITodoRepository repo)
    {
        return repo.Update(id, true);
    }

    public bool DeleteTodo(int id, [Service] ITodoRepository repo)
    {
        return repo.Delete(id);
    }
}

Example Mutation

mutation {
  addTodo(title: "Build GraphQL API") {
    id
    title
    isCompleted
  }
}

10. Dependency Injection & Configuration

10.1 Register Services

builder.Services.AddSingleton<ITodoRepository, TodoRepository>();

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

10.2 Enable GraphQL Endpoint

app.MapGraphQL("/graphql");

Once the app is running, Hot Chocolate provides a built-in GraphQL IDE.

11. Testing the API

Navigate to:

https://localhost:{port}/graphql

You can:

  • Explore schema via documentation panel
  • Run queries and mutations
  • Validate requests automatically

12. Error Handling in GraphQL

GraphQL always returns 200 OK, but errors are included in the response:

{
  "data": null,
  "errors": [
    {
      "message": "Todo not found"
    }
  ]
}

This makes client-side handling predictable.

13. Security Considerations

In real-world applications:

  • Use Authorization directives
  • Limit query depth & complexity
  • Validate input using input types
  • Enable persisted queries

Hot Chocolate supports all of these features.

14. When to Choose GraphQL

GraphQL is ideal when:

  • Multiple clients consume the same API
  • Frontend requirements change frequently
  • You want strong contracts without versioning

Avoid GraphQL when:

  • APIs are extremely simple
  • Heavy HTTP caching is mandatory

15. Conclusion

Implementing GraphQL in .NET using Hot Chocolate provides a clean, scalable, and modern API architecture. Even a simple Todo API demonstrates how GraphQL replaces multiple REST endpoints with a single, powerful schema.

From here, you can extend this API by adding:

  • Entity Framework Core
  • Pagination & filtering
  • Authentication & authorization
  • GraphQL subscriptions for real-time updates
  • GraphQL is a future-proof choice for modern .NET applications.

Happy Coding!

Anubhav Kumar
Anubhav Kumar
Student

The Anubhav portal was launched in March 2015 at the behest of the Hon'ble Prime Minister for retiring government officials to leave a record of their experiences while in Govt service .