GraphQL vs REST in C#: Battle of the Titans or Choosing the Right Tool for the Job?
\n\nHello, colleagues! If you write in C# and create APIs, the question "REST or GraphQL?" has surely come up more than once. It's like arguing about what's better: a hammer or a screwdriver. Both are tools, but for different tasks. In this article, we won't fanatically defend one technology, but will soberly, with C# code examples, analyze when GraphQL wins and when good old REST remains king.
\n\nWe are the PythonLib team, and although the name includes "Python," we love the .NET and C# ecosystem. Today we'll dive into the world of C# APIs and figure out how not to make a mistake with your choice. Let's go!
\n\nQuick Primer: REST and GraphQL for the C# Developer
\n\nREST (Representational State Transfer) is an architectural style we all know and love. In C#, you're most likely using ASP.NET Core Web API. You create controllers, endpoints, and each endpoint returns a fixed data structure. Want to get a user? Go to /api/users/1. Want their orders? Go to /api/users/1/orders. Simple, predictable, but often leads to over-fetching (getting unnecessary data) or under-fetching (needing to make multiple requests).
GraphQL is a query language developed by Facebook. In the C# world, it's implemented through libraries like Hot Chocolate (the most popular) or GraphQL.NET. You have one endpoint (usually /graphql), and the client decides which fields it needs. Want the user's name and only the first order? Please! No over-fetching.
Practical Comparison: C# Code
\n\nLet's move from theory to code. Imagine we have a simple model: User and Order.
// Data Models\npublic class User\n{\n public int Id { get; set; }\n public string Name { get; set; }\n public string Email { get; set; }\n public string Phone { get; set; }\n public List<Order> Orders { get; set; }\n}\n\npublic class Order\n{\n public int Id { get; set; }\n public string ProductName { get; set; }\n public decimal Price { get; set; }\n public DateTime CreatedAt { get; set; }\n}\n\n\nREST API Example on ASP.NET Core
\n\n[ApiController]\n[Route("api/[controller]")]\npublic class UsersController : ControllerBase\n{\n [HttpGet("{id}")]\n public async Task<ActionResult<User>> GetUser(int id)\n {\n // Assume data comes from the database\n var user = await _dbContext.Users.FindAsync(id);\n if (user == null) return NotFound();\n return Ok(user); // Returns ALL fields: Id, Name, Email, Phone, Orders\n }\n}\n\n\nThe problem? If the client only needs the name and email, it still gets Phone and Orders. And if orders are needed, a separate request to /api/users/1/orders must be made.
GraphQL API Example on Hot Chocolate
\n\npublic class Query\n{\n public async Task<User> GetUser(int id, [Service] AppDbContext dbContext)\n {\n return await dbContext.Users.FindAsync(id);\n }\n}\n\n// Registration in Program.cs\nbuilder.Services\n .AddGraphQLServer()\n .AddQueryType<Query>();\n\n\nNow the client can request exactly what is needed:
\n\n// GraphQL query\n{\n user(id: 1) {\n name\n email\n orders {\n productName\n price\n }\n }\n}\n\n\nThe response will contain only name, email, and an array of orders with the fields productName and price. No junk. Beautiful!
When REST in C# Wins (and That's Okay)
\n\n1. Simplicity and Caching. REST APIs are easy to cache at the HTTP level (CDN, proxies). A GET request to /api/products can be cached, and everything is fine.