GraphQL vs REST в C#: Битва титанов или выбор инструмента под задачу?
Привет, коллеги! Если вы пишете на C# и создаете API, то вопрос "REST или GraphQL?" наверняка всплывал не раз. Это как спор о том, что лучше: молоток или шуруповерт. И то, и другое — инструменты, но для разных задач. В этой статье мы не будем фанатично защищать одну технологию, а трезво, с примерами кода на C#, разберем, когда GraphQL выигрывает, а когда старый добрый REST остается королем.
Мы — команда PythonLib, и хотя в названии есть "Python", мы обожаем экосистему .NET и C#. Сегодня заглянем в мир API на C# и разберемся, как не прогадать с выбором. Поехали!
Краткий ликбез: REST и GraphQL для C# разработчика
REST (Representational State Transfer) — это архитектурный стиль, который мы все знаем и любим. В C# вы, скорее всего, используете ASP.NET Core Web API. Вы создаете контроллеры, эндпоинты, и каждый эндпоинт возвращает фиксированную структуру данных. Хотите получить пользователя? Идете на /api/users/1. Хотите его заказы? Идете на /api/users/1/orders. Просто, предсказуемо, но часто приводит к over-fetching (получаете лишние данные) или under-fetching (нужно делать несколько запросов).
GraphQL — это язык запросов, разработанный Facebook. В мире C# его реализуют через библиотеки Hot Chocolate (самая популярная) или GraphQL.NET. У вас один эндпоинт (обычно /graphql), и клиент сам решает, какие поля ему нужны. Хотите имя пользователя и только первый заказ? Пожалуйста! Никакого over-fetching.
Сравнение на практике: C# код
Давайте перейдем от теории к коду. Представим, что у нас есть простая модель: User и Order.
// Модели данных
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public DateTime CreatedAt { get; set; }
}
Пример REST API на ASP.NET Core
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpGet("{id}")]
public async Task<ActionResult<User>> GetUser(int id)
{
// Предположим, что данные приходят из БД
var user = await _dbContext.Users.FindAsync(id);
if (user == null) return NotFound();
return Ok(user); // Возвращаем ВСЕ поля: Id, Name, Email, Phone, Orders
}
}
Проблема? Если клиенту нужно только имя и email, он все равно получит Phone и Orders. А если нужны заказы, придется делать отдельный запрос к /api/users/1/orders.
Пример GraphQL API на Hot Chocolate
public class Query
{
public async Task<User> GetUser(int id, [Service] AppDbContext dbContext)
{
return await dbContext.Users.FindAsync(id);
}
}
// Регистрация в Program.cs
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>();
Теперь клиент может запросить ровно то, что нужно:
// GraphQL запрос
{
user(id: 1) {
name
email
orders {
productName
price
}
}
}
Ответ будет содержать только name, email и массив orders с полями productName и price. Никакого мусора. Красота!
Когда REST в C# побеждает (и это нормально)
1. Простота и кэширование. REST API легко кэшировать на уровне HTTP (CDN, прокси). Запрос GET на /api/products можно закэшировать, и все будут счастливы. С GraphQL кэширование сложнее, так как все запросы — POST (хотя можно и GET), и структура ответа динамическая.
2. Микросервисы и четкие границы. Если у вас микросервисная архитектура на C#, REST часто удобнее. Каждый сервис — это отдельный набор эндпоинтов. GraphQL требует создания единого шлюза (Gateway), что добавляет сложности.
3. Простота для начинающих. REST интуитивно понятен. Вы пишете контроллер, добавляете атрибут [HttpGet] — и готово. GraphQL требует понимания схем, типов, резолверов и, возможно, библиотеки Hot Chocolate.
4. Загрузка файлов. REST справляется с этим отлично через multipart/form-data. В GraphQL это боль: нужно использовать base64, отдельные мутации или сторонние расширения.
Когда GraphQL в C# — это магия
1. Сложные, связанные данные. Представьте дашборд, где нужно показать профиль пользователя, его последние 5 заказов, список избранных товаров и уведомления. На REST вам придется сделать 4 запроса. На GraphQL — один.
2. Мобильные приложения и слабые каналы. Каждый лишний килобайт трафика на мобильном устройстве — это боль пользователя. GraphQL позволяет запросить минимум данных. Отличный пример: клиентское приложение на Xamarin или .NET MAUI.
3. Быстрая итерация фронтенда. Если фронтенд меняется часто, GraphQL спасает. Бэкенд не нужно переписывать под каждую новую фичу. Клиент сам решает, какие поля ему нужны. Это ускоряет разработку.
4. Типизация и документация. GraphQL схемы самодокументируемы. Вы получаете встроенную IDE (GraphQL Playground / Banana Cake Pop), где можно тестировать запросы и смотреть типы. В REST для этого приходится использовать Swagger, что тоже хорошо, но GraphQL дает больше контроля на уровне типов.
Производительность: C# и N+1 проблема
Осторожно! GraphQL может быть медленнее, если не продумать резолверы. Классическая проблема N+1 запросов: вы запрашиваете список пользователей, а для каждого пользователя подгружаете заказы. Если у вас 100 пользователей, будет 1 (список) + 100 (заказы) = 101 запрос к БД.
Решение в C# — DataLoader (встроен в Hot Chocolate). Он батчит запросы.
public class UserResolvers
{
public async Task<IReadOnlyList<Order>> GetOrdersAsync(
[Parent] User user,
[Service] OrderDataLoader dataLoader)
{
return await dataLoader.LoadAsync(user.Id);
}
}
DataLoader соберет все ID пользователей и сделает один запрос к БД. Без