Введение в GraphQL с C#
GraphQL — это язык запросов для API, разработанный Facebook, который предоставляет клиентам возможность запрашивать только те данные, которые им нужны. В отличие от REST, где эндпоинты фиксированы, GraphQL позволяет гибко формировать ответы сервера. В этом туториале мы создадим полноценный GraphQL API на C# с использованием библиотеки Hot Chocolate — самого популярного решения для .NET.
Мы пройдем путь от установки до реализации запросов, мутаций и подписок. К концу статьи вы сможете самостоятельно развернуть GraphQL-сервер на C# и интегрировать его в свои проекты.
1. Установка и настройка проекта
Для начала создадим новый проект ASP.NET Core. Убедитесь, что у вас установлена среда .NET SDK (версия 6.0 или выше). Откройте терминал или командную строку и выполните:
dotnet new web -n GraphQLDemo
cd GraphQLDemo
Теперь установите пакет Hot Chocolate:
dotnet add package HotChocolate.AspNetCore
dotnet add package HotChocolate.AspNetCore.Playground
После установки откройте файл Program.cs и настройте сервер:
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Добавляем GraphQL сервисы
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>();
var app = builder.Build();
// Подключаем middleware GraphQL
app.MapGraphQL();
// Добавляем Playground для тестирования
app.UsePlayground();
app.Run();
Теперь создадим простой класс Query в отдельном файле Query.cs:
public class Query
{
public string Hello() => "Привет, мир GraphQL!";
}
Запустите проект командой dotnet run и откройте браузер по адресу http://localhost:5000/graphql. Вы увидите интерфейс Playground, где можно выполнить запрос:
{
hello
}
Ответ: { "data": { "hello": "Привет, мир GraphQL!" } }
2. Создание типов и запросов
GraphQL строго типизирован. В C# мы используем классы для определения типов. Создадим модель Book и Author:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<Book> Books { get; set; }
}
Теперь добавим хранилище данных (в реальном проекте используйте базу данных) и расширим класс Query:
public class Query
{
private static List<Author> _authors = new()
{
new Author
{
Id = 1,
Name = "Лев Толстой",
Books = new List<Book>
{
new Book { Id = 1, Title = "Война и мир", Author = null },
new Book { Id = 2, Title = "Анна Каренина", Author = null }
}
},
new Author
{
Id = 2,
Name = "Фёдор Достоевский",
Books = new List<Book>
{
new Book { Id = 3, Title = "Преступление и наказание", Author = null }
}
}
};
public List<Author> GetAuthors() => _authors;
public Author GetAuthor(int id) =>
_authors.FirstOrDefault(a => a.Id == id);
public List<Book> GetBooks() =>
_authors.SelectMany(a => a.Books).ToList();
}
Обратите внимание: мы не настраивали явно типы — Hot Chocolate автоматически генерирует схему на основе классов C#. Теперь можно выполнять запросы:
{
authors {
id
name
books {
title
}
}
}
Вы получите только те поля, которые запросили. Это и есть ключевое преимущество GraphQL.
3. Реализация мутаций (изменение данных)
Мутации в GraphQL позволяют изменять данные. Создадим класс Mutation:
public class Mutation
{
public Book AddBook(string title, int authorId)
{
var author = Query._authors.FirstOrDefault(a => a.Id == authorId);
if (author == null)
throw new GraphQLException("Автор не найден");
var book = new Book
{
Id = Query._authors.SelectMany(a => a.Books).Max(b => b.Id) + 1,
Title = title,
Author = author
};
author.Books.Add(book);
return book;
}
}
Зарегистрируйте мутацию в Program.cs:
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>();
Теперь можно выполнить мутацию через Playground:
mutation {
addBook(title: "Идиот", authorId: 2) {
id
title
author {
name
}
}
}
Ответ вернет созданную книгу с данными автора. Обработка ошибок (например, если автор не найден) осуществляется через GraphQLException.
4. Подписки (real-time обновления)
Подписки позволяют клиентам получать обновления в реальном времени через WebSocket. Добавим подписку на добавление новой книги:
public class Subscription
{
[Subscribe]
public Book OnBookAdded([EventMessage] Book book) => book;
}
// Расширяем Mutation:
public class Mutation
{
private readonly ITopicEventSender _eventSender;
public Mutation(ITopicEventSender eventSender)
{
_eventSender = eventSender;
}
public async Task<Book> AddBook(string title, int authorId)
{
// ... код создания книги ...
await _eventSender.SendAsync("BookAdded", book);
return book;
}
}
Зарегистрируйте подписку в Program.cs:
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>()
.AddInMemorySubscriptions();
Подписка выполняется через WebSocket:
subscription {
onBookAdded {
id
title
author {
name
}
}
}
Теперь, когда кто-то добавит книгу через му