Choosing the Right Granularity for Your APIs: Light vs Heavy API Calls
When designing APIs, one of the most important - and often overlooked - decisions is granularity. Should your API calls be lightweight and specific, fetching or modifying just one thing at a time? Or should they be heavyweight and aggregated, returning a bundle of data or performing multiple operations at once?
Let’s explore how to make that decision thoughtfully, based on performance, maintainability, user experience, and real-world use cases.
What Do We Mean by API Granularity?
Granularity refers to how much work a single API call performs:
- Fine-grained (lightweight) APIs perform small, specific tasks, e.g., GET /user/123/profile-picture.
- Coarse-grained (heavyweight) APIs do larger or aggregated tasks, e.g., GET /user/123/dashboard-data (which might include profile, recent activity, and recommendations in one call).
Both approaches have their place. The key is balancing the trade-offs based on your system’s goals.
When to Prefer Lightweight (Fine-Grained) APIs
Use when:
- You need flexibility for frontend teams to mix and match data.
- Data is frequently changing, and small pieces need to be refreshed independently.
- There are strict caching or performance constraints - smaller payloads are faster to transfer.
- You're building a microservice that should do one thing well and stay loosely coupled.
Risks:
- Chatty APIs - too many round trips between client and server can degrade performance, especially on high-latency networks.
- Increased complexity on the client side — clients must now orchestrate multiple API calls.
Example:
GET /products/123
GET /products/123/reviews
GET /products/123/inventory
This gives flexibility but could require three separate round trips.
When to Prefer Heavyweight (Coarse-Grained) APIs
Use when:
- A client consistently needs multiple data elements together - like a mobile app loading a dashboard.
- Reducing latency and number of HTTP calls is a priority.
- You want to encapsulate orchestration logic on the backend rather than exposing it to clients.
- You're building GraphQL-style endpoints or BFFs (Backend-for-Frontend) - I will discuss this pattern in a separate blog.
Risks:
- Potential over-fetching - returning data the client doesn’t always need.
- Tighter coupling - changes to a backend schema may require more coordination across teams.
- Difficult to cache partial data or maintain modularity.
Example:
GET /dashboard
This could return the user profile, order history, loyalty points, and recommendations in a single response.
How to Decide Granularity: 6 Questions to Ask
- What’s the client context?
Mobile apps with high-latency networks benefit from heavier APIs. Internal systems on fast networks can afford more granular calls.
- What’s the usage pattern?
If clients always need data A and B together, merge them. If they rarely co-occur, keep them separate.
- Are you building for reuse or speed?
Reusable, generic APIs tend to be lightweight. Purpose-specific APIs (e.g., /checkout-summary) can be heavier but optimized.
- How often does each piece of data change?
Granular APIs let you cache and refresh small parts individually.
- How will versioning be managed?
Smaller APIs are easier to evolve independently. Coarse-grained ones may need more careful version control.
- Is this API internal or public?
Public APIs should be stable and consistent — often leading to cleaner, more granular endpoints. Internal APIs can afford more opinionated or aggregated structures.
There’s no one-size-fits-all rule for API granularity. Like many architectural decisions, it's a trade-off — between performance and flexibility, between decoupling and convenience. A good API design is one that reflects real user needs while remaining scalable and maintainable.