Best Practices Summary
For REST in .NET:
- Use projection to DTOs (
Selectinstead of.Include()when possible). - Define endpoint-specific contracts to prevent over-fetch.
- Use
AsNoTrackingand async LINQ queries for read APIs.
For GraphQL in .NET:
- Use DataLoader pattern to batch N+1 queries.
- Limit query depth & complexity for protection.
- Cache persisted queries when possible.
Over-fetching
- The client receives more data than it needs.
- Example:
GET /users/1returns the entire user entity including addresses, settings, history, but the UI only needsnameandemail. - Downsides: unnecessary CPU, bandwidth, and serialization cost.
Under-fetching
- The client receives too little data, requiring multiple round-trips.
- Example:
GET /orders/1returns order header only. The UI then must call/orders/1/itemsand/orders/1/payments. - Downsides: chatty APIs, high latency.
2. REST vs GraphQL
2.1) REST APIs
-
Pros:
- Simple, mature, widely supported in .NET (
Minimal APIs,ASP.NET Core MVC). - Strong HTTP semantics (GET/PUT/POST/DELETE, caching, status codes).
- Easy to secure with middleware and API gateways.
- Straightforward to implement with EF Core projections.
- Simple, mature, widely supported in .NET (
-
Cons:
- Fixed shape: risk of over/under-fetching.
- For complex UI, clients may need multiple calls.
Narrow-down DTOs, Includes, and Projections in REST
- Narrowed-down response models designed for specific endpoints, preventing accidental over-fetch.
- Example:
UserProfileDtowith only the fields needed for a profile screen.
Includes
- In EF Core,
.Include()lets you load related entities in a single query. - Use carefully: it prevents under-fetching but may over-fetch if you pull deep graphs unnecessarily.
Projections
- Selecting only the needed fields directly from the DB into DTOs.
- Example:
var users = db.Users
.Select(u => new UserDto(u.Id, u.Name, u.Email))
.ToListAsync();
- This is the most efficient pattern for REST endpoints—avoids both over-fetching and under-fetching.
2.2) GraphQL
-
Pros:
- Client defines exactly what fields it wants (solves over/under-fetching elegantly).
- Single endpoint can serve multiple client needs.
- Great for frontend-heavy apps (React/Angular/Blazor with many nested queries).
-
Cons:
- Processing cost: server parses & validates dynamic queries → heavier than REST.
- Memory: query execution may hydrate large graphs before resolving → higher pressure than REST projections.
- Complexity: harder caching, monitoring, and securing (need query depth limits, persisted queries, etc.).
- In .NET (HotChocolate, GraphQL.NET): performance is good, but raw REST with EF Core projection is still faster when payload size doesn’t matter.
3. Which is Better in .NET Core
Assuming payload size is irrelevant
Processing time:
REST with EF Core projection is faster because the SQL is pre-shaped and predictable. GraphQL incurs query parsing and field resolution overhead.Memory usage:
REST wins again; GraphQL’s resolver pipeline often materializes intermediate objects.Raw speed (throughput):
REST (properly designed DTO + projection) usually achieves higher RPS (requests per second). GraphQL trades some speed for flexibility.-
When GraphQL shines:
- Complex UI with many optional fields.
- B2B integrations where clients vary widely in what they need.
- Cases where reducing network calls is more important than raw speed.
-
When REST is better:
- Internal services and backends where contracts are stable.
- High-throughput scenarios (10M+ rows, heavy pagination).
- APIs where performance predictability is critical.
✅ My recommendation
10M+ data, high performance, payload size doesn’t matter
- Stick with REST + EF Core projections + keyset pagination.
- Add GraphQL only if your consumers demand flexible queries across complex object graphs.
Top comments (0)