Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ArchitectureJune 23, 20264 min read

REST API Field Selection: Solving Data Over-fetching and Dependency Graphs

REST API field selection allows clients to request only the data they need. Learn to implement GraphQL-style patterns to stop data over-fetching today.

REST APIAPI DesignSystem ArchitectureGraphQLPerformance OptimizationBackend EngineeringAPIArchitectureBackendSystem Design

Last month, we spent three days debugging a latency spike on our user-profile service that turned out to be a classic case of data over-fetching. Our mobile client was pulling a 450KB JSON blob just to display a username and a profile picture, forcing the backend to join four different tables and aggregate data from a secondary cache. We were drowning in unnecessary I/O.

If you’re building a REST API, you’ve likely hit the wall where your resources become too bloated to be efficient. While we often look at REST API Resource Partial Updates to fix write operations, the read side—specifically how we handle complex resource fetching—is where most systems bleed performance.

Implementing GraphQL-Style Field Selection in REST

The goal isn't to abandon REST for GraphQL; it's to borrow the best parts of its type system to improve your current architecture. We want to give the client control over the response shape without introducing the overhead of a full GraphQL engine.

We started by implementing a fields query parameter that acts as a projection layer. Instead of returning the full resource, the API inspects the fields parameter and prunes the response object before serialization.

The Problem with Naive Projection

We first tried a naive approach: regex-based filtering on the final JSON string. It broke almost immediately.

  1. Depth issues: We couldn't handle nested objects without writing a recursive nightmare.
  2. Performance: String manipulation on large payloads is slow and memory-intensive.
  3. Dependency Hell: If a client requested user.orders, but orders required a specific auth scope or a different database shard, the logic became spaghetti.

Moving to Dependency Graphs

To solve this, we moved to a dependency-aware resolver. Each field in our resource model now maps to a "provider" function. When a request comes in, we parse the fields string into a tree structure and execute only the providers required for that specific request.

Here’s a simplified look at how we handle this in a Go-based service:

Go
type User struct {
    ID       string `json:"id"`
    Name     string `json:"name"`
    Orders   []Order `json:"orders,omitempty"`
}

// Resolver logic snippet
func ResolveUser(ctx context.Context, fields []string) (*User, error) {
    user := &User{ID: "123", Name: "Mahamudul"}
    
    // Check if 'orders' is in the requested fields
    if contains(fields, "orders") {
        user.Orders = fetchOrdersForUser(user.ID)
    }
    return user, nil
}

This pattern forces you to be explicit about your API Design Schema Evolution. By mapping fields to specific data-loading functions, you naturally create a dependency graph. If orders is requested, the system knows it needs to hit the order database; if not, it skips that query entirely.

Balancing System Scalability and Complexity

Adopting this pattern provides a massive boost to system scalability. By reducing payload sizes and avoiding unnecessary database joins, we cut our average response time by roughly 1.8x.

However, there is a cost. You’re moving complexity from the database to the application layer. You must ensure that your resolver functions are idempotent and don't introduce N+1 query problems. I recommend using a data loader pattern (similar to the Facebook/DataLoader implementation) to batch requests if multiple fields require data from the same source.

FAQ: Common Pitfalls

Q: Doesn't this make caching harder? A: Yes. Your cache keys must now include the fields parameter. We use a hashed version of the requested field list as part of our cache key to avoid collisions.

Q: How do you handle validation for the fields parameter? A: We treat the fields parameter as a whitelist. If a client requests a field that doesn't exist or isn't allowed for their role, the API returns a 400 Bad Request. Never let the client dictate arbitrary internal data access.

Q: Is this overkill for simple CRUD? A: Probably. If your resources are small and stable, just stick to standard REST. This pattern pays for itself only when your resource graphs become deep and the cost of fetching a "full" resource starts impacting your database throughput.

Final Thoughts

We’re still refining how we document these dynamic responses. OpenAPI/Swagger doesn't handle conditional field selection perfectly, so we’ve had to supplement our documentation with custom examples.

If I were starting this from scratch, I’d spend more time on the parsing layer. We spent about two days just fixing edge cases in how nested fields were parsed from the query string. It’s not a perfect solution, but for our scale, it’s the bridge that keeps our REST architecture performant without the complexity of switching tech stacks entirely.

Back to Blog

Similar Posts

Real estate investment concept with money and house models on table.
ArchitectureJune 20, 20264 min read

REST API design choices that scale without technical debt

REST API design choices dictate your system's longevity. Learn the patterns that prevent breaking changes, simplify client integration, and scale reliably.

Read more
ArchitectureJune 23, 2026
4 min read

REST API Design: Mastering Content Negotiation for Schema Evolution

Master REST API design using content negotiation. Learn how to leverage Accept headers to handle schema evolution and multiple data formats like a pro.

Read more
ArchitectureJune 23, 20264 min read

API Rate Limiting with Token Bucket Algorithms for Multi-Tenant SaaS

Master API rate limiting using the token bucket algorithm to protect your multi-tenant SaaS. Learn to handle distributed traffic shaping with zero downtime.

Read more