When Should You Use Fine‑Grained vs Coarse‑Grained Resources in REST APIs?
This article explains how to choose between fine‑grained and coarse‑grained resource designs in REST APIs, illustrating trade‑offs with blog‑post examples, showing how to model business processes as intent resources, and discussing the impact of avoiding PUT in favor of CQRS.
Preface
“The core abstraction of information in REST is the resource. Anything that can be named can be a resource: documents, images, temporary services, collections, non‑virtual objects, etc.” – Roy Fielding.
Resources form the foundation of any REST API. Resource identifiers (URIs), representations, and HTTP methods are built around the resource concept. Properly modeling resources at the right granularity ensures that API consumers get the needed functionality while keeping the API maintainable.
1 Fine‑Grained vs Coarse‑Grained Resources
Designing APIs around very fine‑grained resources leads to many endpoints and frequent client‑server interactions, increasing load and complexity. Conversely, overly coarse‑grained resources that try to do everything can become hard to use and maintain. A blog‑post API illustrates the trade‑off:
Multiple fine‑grained endpoints for title, content, images, tags, etc., causing many HTTP requests.
A single coarse‑grained endpoint that creates a post with all fields in one request, reducing server load.
However, using a single coarse‑grained Post resource for actions like “like” or “comment” forces the provider to interpret intent from the payload, adding complexity on both sides.
1.1 Preventing Business Logic from Leaking to API Consumers
Fine‑grained APIs push business rules (e.g., a post must have tags, images must be present before tagging) onto the client. This creates consistency problems when requests succeed or fail out of order, and it ties client code to server‑side domain knowledge, making updates costly across many consumer types.
Coarse‑grained designs keep business logic on the server, shielding consumers from internal rules and reducing the need for client‑side changes when the domain evolves.
2 Business‑Process‑Oriented Coarse‑Grained Aggregate Resources
Complex workflows can be modeled as resources themselves. For example, a “CustomerEnrollment” resource represents the whole onboarding process, while a “ChangeOfAddress” resource captures an address‑change event with full audit data. Modeling such intent resources keeps the API expressive and decouples clients from low‑level domain details.
2.1 Moving Away from CRUD
Two approaches to updating a customer’s address:
Directly PUT to the Customer or Address resource, which discards valuable event data and couples the client to the domain model.
POST to a ChangeOfAddress intent resource, preserving who made the change, when, and what changed, while keeping the client agnostic to internal structures.
This shift ensures that only the service that owns the state can modify it, and optional event persistence can be decided based on business value.
2.2 Nouns vs Verbs
Choosing noun‑based resource names (e.g., CustomerEnrollment) aligns API design with business language, making it easier to query the current state of a long‑running process and to evolve the underlying implementation without breaking clients.
2.3 Concretizing Abstract Concepts
Examples:
Cash deposit in a bank modeled as a Transaction resource rather than directly updating an Account.
Money transfer between accounts modeled as a MoneyTransfer or Transaction resource, allowing the operation to be tracked as a distinct entity.
These concrete resources act as transaction boundaries and can be queried independently of the low‑level account resources.
3 “No‑PUT” REST and CQRS
Replacing PUT updates with POST to intent resources aligns with event sourcing and naturally separates command (C) and query (Q) sides. Clients POST a ChangeOfAddress resource, then later GET the updated Customer view, accepting eventual consistency while preserving rich event data.
4 Example from GitHub Public API
GitHub’s API demonstrates balanced granularity: a Forks sub‑collection lets you list or create forks (coarse‑grained), while low‑level resources like Tag remain available for detailed operations.
5 Conclusion
There is no one‑size‑fits‑all solution. Simple data retrieval (e.g., account balance) can use fine‑grained resources, whereas complex workflows (e.g., fund transfers, enrollment) benefit from coarse‑grained, intent‑oriented resources. Choose the granularity that matches business needs, technical constraints, and maintenance considerations to deliver the best consumer experience.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
