Take a Closer Look at REST
You might be surprised at what you‘re missing!
Developers often favor RPCs due to the similarities of RPCs to local procedure calls, their perceived efficiency, and their familiar tooling. However, this preference can stem from a lack of understanding of REST’s principles and advantages in distributed environments.
While RPCs can excel in tightly coupled, performance-critical applications — REST is generally superior for scalable, loosely coupled, and interoperable applications — especially in large-scale or heterogeneous distributed systems.
Let’s take a look at why REST and RPCs are so different.
REST’s foundation is in distributed computing constraints and RPC’s foundation is in mimicking local procedure calls. This has profound implications for their differences in scalability, robustness, simplicity, and suitability for building distributed systems.
REST’s Foundation in Distributed Computing Constraints
REST was defined to explicitly address the challenges and realities of distributed systems. Its architectural constraints are deeply tied to the inherent difficulties of networked environments, such as:
Latency
- REST acknowledges that network communication is inherently slower than local communication.
- It optimizes for fewer, self-contained interactions by leveraging statelessness and caching.
- Example: Caching responses for GET requests reduces the need for repeated round trips to the service.
Partial Failures
- REST is designed for fault tolerance in distributed environments, where network partitions and partial failures are common.
- Statelessness ensures that services don’t need to coordinate state across nodes, and clients can retry requests independently.
Scalability
- REST’s statelessness and resource-oriented design simplify horizontal scaling, which is crucial for distributed systems with unpredictable workloads.
- Example: A load balancer can distribute stateless REST requests evenly across multiple servers without concern for session affinity.
Heterogeneity
- REST embraces the heterogeneity of distributed systems by using universal standards (HTTP, URIs, JSON, etc.) for communication.
- Clients and services can interact seamlessly, even if built with different technologies.
Independent Evolution
- REST’s loosely coupled architecture allows clients and services to evolve independently, provided they adhere to the defined API contracts.
- Hypermedia (HATEOAS) enables dynamic workflows without requiring the client to have prior knowledge of all possible service states.
RPC’s Mimicry of Local Procedure Calls
RPC, in contrast, is rooted in the paradigm of local procedure calls, attempting to abstract away the complexities of distributed systems. While this approach can simplify programming for developers, it introduces significant challenges in distributed environments. The assumptions behind RPC:
Transparency
- RPC aims to make remote calls appear identical to local procedure calls by abstracting network communication.
- This abstraction, while convenient, hides the realities of network latency, partial failures, and bandwidth limitations.
Synchronous Communication
- RPC often assumes synchronous, blocking communication, which is well-suited for local calls but problematic in distributed systems where delays or failures are common.
Tight Coupling
- RPC systems typically couple clients and services tightly through method definitions and protocols, making changes more difficult and reducing flexibility.
- Example: Modifying an RPC method often requires updating and redeploying both client and service.
Statefulness
- Many RPC implementations rely on maintaining session state on the server side — complicating scaling and failover.
Key Implications
Scalability
REST:
- REST’s statelessness allows any service of the same type to handle any request, simplifying load balancing and enabling seamless horizontal scaling.
- Caching reduces server load by allowing intermediaries or clients to store and reuse responses.
- REST is inherently designed for large-scale distributed systems (like the Web itself).
RPC:
- Stateful interactions make scaling challenging because session state must be managed, synchronized, or routed to specific servers.
- RPC lacks built-in caching mechanisms, meaning every call typically requires a direct interaction with the service.
- Scaling RPC-based systems often requires complex state replication or affinity routing.
Fault Tolerance
REST:
- Stateless interactions and idempotent operations (PUT, DELETE) ensure that clients can retry failed requests without introducing inconsistencies.
- REST embraces partial failures: clients can recover or retry independently, and caching mitigates issues during temporary outages.
- Example: If a GET request fails, a client can retry the same URI without risking side effects.
RPC:
- RPC systems often fail when partial failures occur because the client assumes the call is atomic, like a local procedure call.
- Retries are complicated by potential side effects (such as a partially completed database transaction).
- Network errors can break the illusion of locality, requiring developers to explicitly handle failures.
Simplicity
REST:
- REST’s use of universal standards (HTTP, JSON, URIs) simplifies development and integration across heterogeneous systems.
- The uniform interface reduces cognitive load for developers: interacting with one REST resource is conceptually the same as interacting with another.
- Example: A developer interacting with GET /user can intuitively understand how to interact with GET /order.
RPC:
- RPC’s abstraction of remote calls as local calls simplifies initial development but creates complexity in debugging, error handling, and scaling.
- Tight coupling between clients and services requires coordinated updates, increasing maintenance overhead.
- Example: Adding a new parameter to an RPC method often requires regenerating and redeploying client stubs.
Flexibility
REST:
- REST’s resource-oriented design and hypermedia controls (HATEOAS) enable dynamic workflows and loose coupling between components.
- Clients can navigate workflows or discover new resources dynamically through links provided in responses.
- Example: A REST API response for a POST /ticket request might include a link to GET /ticket/{id} for further actions.
RPC:
- RPC systems are tightly coupled to predefined methods, making workflows rigid and harder to adapt to changing requirements.
- Clients must know all available methods and their parameters ahead of time, limiting flexibility.
- Example: Adding a new workflow step might require defining a new RPC method and updating all clients.
Debugging and Maintenance
REST:
- Debugging REST interactions is simpler because HTTP requests and responses are human-readable and use standard tools (like curl, Postman).
- REST APIs are self-descriptive, with clear resource representations and HTTP status codes indicating success or failure.
RPC:
- RPC interactions are harder to debug due to opaque serialization formats (Protocol Buffers!) and complex transport protocols.
- Errors often require examining low-level network traces or protocol-specific logs.
Conclusion
REST is inherently superior for distributed systems because it explicitly embraces the constraints of distributed computing: latency, partial failure, scalability, and heterogeneity.
By contrast, RPC’s attempt to mimic local calls abstracts away these constraints, often leading to systems that are harder to scale, less fault-tolerant, and more rigid.
While RPCs may be suitable for tightly controlled environments, REST’s flexibility and resilience make it the better choice for large-scale, heterogeneous distributed systems.
Getting It Right
One of the most serious problems facing the adoption of REST is the sheer volume of misunderstanding and misinformation surrounding it.
All too often, “RESTful” APIs are merely RPCs packaged for transmission over HTTP and fail to implement REST architectural principles. That can also be true of many “REST” APIs.
The value of the REST architectural pattern derives from the constraints it enforces. If you ignore or fail to understand those constraints you lose the value.
The most accurate and information-rich description of REST is in Roy Fielding’s own doctoral thesis, CHAPTER 5 — Representational State Transfer (REST). It is a serious exercise in professional software architecture — but it is well worth the effort to learn and understand. When it comes to networked and distributed software architecture, it is the definitive work.
Thanks for reading!
Your questions and comments are very welcome.
We know that this article has just scratched the surface of the differences between REST and RPCs. We’re trying to get a serious conversation started so we can continue to share what we’ve learned — and so we can add your experiences to the mix!
If you found this discussion useful, a clap would let us know that you are interested.
Suggested reading: A Transformative Approach to Distributed Applications