Introduction: Why GraphQL and C# Are the Perfect Pair
\nModern web development requires flexible and efficient APIs. REST API, despite its popularity, often suffers from over-fetching (retrieving unnecessary data) and under-fetching (needing multiple requests to get complete information). GraphQL solves these problems by allowing the client to request only what it needs in a single request.
\nIn this tutorial, we will build a full-fledged GraphQL API in C# using the Hot Chocolate library — the most popular GraphQL implementation for .NET. You will learn how to set up a server, define a schema, implement queries, mutations, and subscriptions. All code examples are practical and ready to use.
\nWho this material is for: .NET developers who want to learn GraphQL, and those looking for an alternative to REST. Basic knowledge of C# and ASP.NET Core will be helpful but is not required.
\n\n1. Project Setup and Installing Hot Chocolate
\nCreating an ASP.NET Core Project
\nLet's start by creating a new project. Open a terminal or command prompt and run:
\ndotnet new web -n GraphQLDemo\ncd GraphQLDemo\nNow install the Hot Chocolate package:
\ndotnet add package HotChocolate.AspNetCore\ndotnet add package HotChocolate.AspNetCore.Playground\nThe HotChocolate.AspNetCore package adds middleware for handling GraphQL requests, and HotChocolate.AspNetCore.Playground provides a built-in IDE (GraphQL Playground) for testing.
Startup Configuration
\nEdit the Program.cs file (or Startup.cs for .NET 5 and below). Add the basic configuration:
var builder = WebApplication.CreateBuilder(args);\n\n// Add GraphQL services\nbuilder.Services\n .AddGraphQLServer()\n .AddQueryType<Query>()\n .AddMutationType<Mutation>(); // will add later\n\nvar app = builder.Build();\n\n// Add middleware\napp.UseRouting();\napp.MapGraphQL(); // endpoint /graphql\napp.MapGraphQLPlayground(); // Playground available at /playground\n\napp.Run();\nNote: Query and Mutation are classes we will create next. For now, let's keep only Query.
2. Creating the Data Model and First Query
\nBook Model
\nLet's create a simple book model. Add the file Models/Book.cs:
namespace GraphQLDemo.Models;\n\npublic class Book\n{\n public int Id { get; set; }\n public string Title { get; set; } = string.Empty;\n public string Author { get; set; } = string.Empty;\n public int Year { get; set; }\n public decimal Price { get; set; }\n}\n\nQuery Class
\nNow let's create the Query class, which will contain methods for retrieving data. Add the file GraphQL/Query.cs:
using GraphQLDemo.Models;\n\nnamespace GraphQLDemo.GraphQL;\n\npublic class Query\n{\n // Temporary data storage (in a real project — database)\n private static readonly List<Book> Books = new()\n {\n new Book { Id = 1, Title = "War and Peace", Author = "Leo Tolstoy", Year = 1869, Price = 29.99m },\n new Book { Id = 2, Title = "Crime and Punishment", Author = "Fyodor Dostoevsky", Year = 1866, Price = 24.99m },\n new Book { Id = 3, Title = "The Master and Margarita", Author = "Mikhail Bulgakov", Year = 1967, Price = 19.99m }\n };\n\n // Query: get all books\n public IQueryable<Book> GetBooks() => Books.AsQueryable();\n\n // Query: get a book by ID\n public Book? GetBookById(int id) => Books.FirstOrDefault(b => b.Id == id);\n}\nMethods that return data are called resolvers. Hot Chocolate automatically