RPC vs REST: what's the difference, and which should you use?
RPC calls a named procedure on a server; REST sends requests to resources through HTTP's uniform interface. A side-by-side comparison with gRPC and JSON-RPC examples, from Fielding, RFC 9110 and the specs.
Beginner10 min read
RPC call a procedure ┌────────┐ POST /UserService/GetUser ┌──────────┐ │ client │ ────────────────────────────────────────│ server ● │ └────────┘ { "id": 42 } └──────────┘ ← { "name": "..." } ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ REST ask for a resource ┌────────┐ GET /users/42 ┌──────────┐ │ client │ ────────────────────────────────────────│ server ● │ └────────┘ └──────────┘ ← 200 OK { "name": "..." }
On this page
The short answer: RPC calls a procedure on another machine by name, passes it parameters and waits for the result. REST sends requests to resources, each with its own URL, using HTTP's standard methods such as GET and DELETE, which work the same way on every resource.
Both can run over HTTP, so the difference is not the protocol. It is what the request names. If it names a function, such as GetUser, it is RPC. If it names a piece of data, such as /users/42, and lets the method say what to do with it, it follows REST.
RPC call a procedure ┌────────┐ POST /UserService/GetUser ┌──────────┐ │ client │ ────────────────────────────────────────│ server ● │ └────────┘ { "id": 42 } └──────────┘ ← { "name": "..." } ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ REST ask for a resource ┌────────┐ GET /users/42 ┌──────────┐ │ client │ ────────────────────────────────────────│ server ● │ └────────┘ └──────────┘ ← 200 OK { "name": "..." }
What is RPC?
RPC stands for Remote Procedure Call: calling a function that lives on another machine as if it were part of your own program. Roy Fielding describes RPC this way: the protocol identifies the procedure and passes it a fixed set of parameters, and then waits for the answer (section 6.5.2).
RFC 5531, the specification for ONC RPC version 2, describes the same flow. The caller sends a call message to the server and waits (blocks) for a reply message. The same RFC warns that a remote call is not really a local one: error handling is different, there are no shared global variables, the caller has to authenticate, and remote procedures usually operate at one or more orders of magnitude slower than local ones.
In gRPC, a widely used RPC framework, the client calls methods on a generated stub as if it were a local object, even though the method runs on another machine.
What is REST?
REST stands for Representational State Transfer. It is an architectural style that Roy Fielding set out in chapter 5 of his 2000 PhD dissertation at the University of California, Irvine, for distributed hypermedia systems. REST is not a protocol or a library. It is a set of constraints a system follows.
The core unit is the resource. Fielding's definition: any information that can be named can be a resource, such as a user, a document or a list of orders. What travels between client and server is not the resource itself but a representation of it: a sequence of bytes, plus representation metadata to describe those bytes, for example the JSON or HTML for that user.
The constraints in chapter 5 (Fielding, section 5.1):
| Constraint | What it means |
|---|---|
| Client-server | Client and server concerns are kept separate |
| Stateless | Each request carries everything the server needs to understand it; session state stays on the client |
| Cache | Responses must be labelled cacheable or non-cacheable |
| Uniform interface | Every resource is used through the same interface; Fielding calls this the central feature that sets REST apart |
| Layered system | Each component sees only the layer next to it, so proxies, caches and gateways can sit in between |
| Code-on-demand | The server may send code for the client to run; the only optional constraint |
The uniform interface has four parts of its own: identification of resources, manipulation of resources through representations, self-descriptive messages, and hypermedia as the engine of application state, often shortened to HATEOAS.
HTTP is built along the same lines. RFC 9110 (June 2022) says HTTP provides a uniform interface for interacting with a resource regardless of its type, nature, or implementation, and that its standard methods are not resource-specific (section 9.1).
How are RPC and REST different?
Take one task, fetching user 42, and do it both ways. In JSON-RPC 2.0 the method name and parameters go in the body (JSON-RPC 2.0 Specification):
{"jsonrpc": "2.0", "method": "getUser", "params": {"id": 42}, "id": 1}
In REST over HTTP the resource goes in the URL and the method says what to do:
GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
From these two requests, the differences fall into five areas.
What does the request name?
RPC names an action. In JSON-RPC that is the method member, the name of the method to be invoked. In gRPC it is the path /Service-Name/method name, for example /UserService/GetUser.
REST names data: the URL of a resource such as /users/42, with the same methods used on every resource. Fielding puts the difference this way: in HTTP, requests are directed to resources using a generic interface with standard semantics that can be interpreted by intermediaries, while RPC mechanisms are defined in terms of language APIs.
Does the HTTP method mean anything?
In REST, yes: RFC 9110 defines it. GET, HEAD, OPTIONS and TRACE are defined to be safe, meaning they should not change anything on the server. PUT, DELETE and all safe methods are idempotent: sending one twice has the same effect as sending it once. POST is in neither group.
In RPC over HTTP, the method usually tells you little. gRPC sends every call as POST with content-type application/grpc, whether the method reads data or deletes it. The meaning is in the method name, which only the client and server understand.
How do errors come back?
REST over HTTP uses HTTP status codes. The first digit defines the class of response: 2xx success, 4xx client error, 5xx server error. If user 42 does not exist, the answer is 404 Not Found.
RPC protocols define their own errors. JSON-RPC returns an error object with code, message and data; -32601 means Method not found:
{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": 1}
gRPC has its own status codes, from 0 (OK) to 16 (UNAUTHENTICATED), sent in a grpc-status trailer. A gRPC error response uses HTTP status 200 (OK), so the HTTP status alone does not tell you whether the call worked.
Is it safe to retry?
This matters when the network fails. Because some HTTP methods are idempotent, RFC 9110 says such a request can be repeated automatically if a communication failure occurs before the client is able to read the server's response. A client, proxy or library can retry a GET or PUT without knowing anything about the API.
RPC has no shared rule like this. RFC 5531 says that if a client retransmits a call and gets one reply, it cannot infer anything about the number of times the procedure was executed, only that it ran at least once. gRPC's note on UNAVAILABLE says the same: it is not always safe to retry non-idempotent operations. The API designer has to say which methods can be retried.
What can caches and other intermediaries do?
REST requires every response to be labelled as cacheable or non-cacheable, and because every resource has the same interface, caches, proxies and gateways can understand requests without knowing the API.
That has a cost, and Fielding states it himself: a uniform interface degrades efficiency, since information is transferred in a standardized form rather than one which is specific to an application's needs. Statelessness may decrease network performance because the same data is sent again with every request. RPC makes the opposite trade: methods and message formats fit each task, and intermediaries understand less of what passes through them.
Side by side:
| RPC | REST | |
|---|---|---|
| The request names | A procedure and its parameters | A resource URL |
| HTTP method | Usually POST for everything, or no HTTP at all |
Defined by RFC 9110 |
| Errors | The protocol's own format, e.g. a JSON-RPC error object or grpc-status |
HTTP status codes |
| Automatic retry | Only if you know the method is idempotent | Decided from the method |
| Caches and proxies | Understand little | Understand requests, since the interface is the same for every resource |
| Contract | An IDL or a per-method spec | URLs, methods and media types |
Is every HTTP API a REST API?
No. In his dissertation Fielding writes that people often mistakenly refer to HTTP as a remote procedure call (RPC) mechanism simply because it involves requests and responses. In a 2008 blog post he looked at one API sold as a "REST API" and said plainly: "That is RPC."
His test is that if the engine of application state is not being driven by hypertext, then it cannot be RESTful. A client should start with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types and follow the links the server sends back.
By that test, most APIs that call themselves REST use only part of it: resource URLs and HTTP methods with their proper meaning, but no hypermedia. That does not make them bad APIs. It is worth knowing which of REST's properties you get and which you don't.
How do gRPC and JSON-RPC work?
JSON-RPC 2.0 is a stateless, light-weight remote procedure call (RPC) protocol and is transport agnostic, so it can run over HTTP, WebSocket or anything else. A request has four members: jsonrpc (exactly "2.0"), method, params (optional) and id. Leave out id and it becomes a notification, which the Server MUST NOT reply to. Several requests can be sent together as an array, and the responses may be returned in any order, so they are matched by id.
gRPC is an RPC framework with HTTP/2-based transport. It uses Protocol Buffers as its IDL (Interface Definition Language) by default. You describe services and messages in a .proto file and generate client and server code from it:
service UserService {
rpc GetUser (GetUserRequest) returns (User);
}
gRPC has four kinds of service method: unary (one request, one response), server streaming, client streaming and bidirectional streaming. A client can set a deadline; a call that runs past it ends with DEADLINE_EXCEEDED. If a call is cancelled midway, changes made before a cancellation are not rolled back.
The common catch is the browser. Browsers do not expose HTTP/2 framing, so web clients use gRPC-Web, which implements a different protocol than the native gRPC protocol. gRPC's own web tutorial puts an Envoy proxy between the browser and the server.
Can one API mix both?
Yes. Google's API Improvement Proposals (AIPs) are a clear example. They describe resource-oriented design as a pattern for specifying RPC APIs that borrows many principles from REST.
Such an API has five standard methods, Get, List, Create, Update and Delete, which map to working with resources, and the AIP says APIs should prefer standard methods over custom methods. When a task does not fit, a custom method gives the same design freedom as traditional RPC APIs. The URL uses : followed by the verb (AIP-136):
POST /v1/publishers/123/books/456:archive
The order AIP-130 recommends is standard methods first, then batch or aggregate methods, then custom methods, and streaming methods last (AIP-130).
What does this mean for network security?
First, what a firewall or proxy can see. With REST, an intermediary can tell from the method whether a request reads or writes, and from the status code how it ended. With gRPC, every call is a POST to a different path, and the HTTP status is 200 even when the call fails (PROTOCOL-HTTP2). Logs that keep only the method and status code cannot separate failed calls from successful ones; you need the path and grpc-status too.
Second, layers. Fielding writes that a layered system lets security policies be enforced on data crossing the organizational boundary, as is required by firewalls. Elsewhere he calls using HTTP to move other application protocols through a firewall "a fundamentally misguided idea" (section 6.5.3). When every request looks like the same POST, a policy based on the method alone cannot tell them apart.
Which one should you use?
Neither is better everywhere. Start from what the job needs:
- An API used by many different clients, especially browsers: REST over HTTP fits better. Methods, status codes and caching are understood by every tool; gRPC needs gRPC-Web and a proxy.
- Internal services that talk a lot and need a strict contract: gRPC gives you a
.protofile as the shared contract, generated code, deadlines and streaming. - Continuous data in both directions: gRPC has bidirectional streaming built into the protocol.
- Actions that are not reads or edits, such as "archive" or "start a job": use a custom method in the AIP-136 style instead of forcing it into a resource.
- A small RPC protocol not tied to any transport: JSON-RPC 2.0 is just JSON and a short spec.
Whichever you pick, write down two things in the API docs: which methods can be retried, and what each kind of error looks like. Those are the two places where RPC and REST differ most.
Sources
- Roy Fielding (2000): Architectural Styles and the Design of Network-based Software Architectures
- Roy Fielding (2000): Chapter 5, Representational State Transfer (REST)
- Roy Fielding (2000): Chapter 6, Experience and Evaluation
- Roy Fielding (2008): REST APIs must be hypertext-driven
- RFC 9110: HTTP Semantics
- RFC 5531: RPC: Remote Procedure Call Protocol Specification Version 2
- JSON-RPC 2.0 Specification
- gRPC
- gRPC: Introduction to gRPC
- gRPC: Core concepts, architecture and lifecycle
- gRPC: Status codes
- gRPC over HTTP2 (PROTOCOL-HTTP2.md)
- gRPC Web (PROTOCOL-WEB.md)
- gRPC: Basics tutorial for Web
- Google AIP-121: Resource-oriented design
- Google AIP-130: Methods
- Google AIP-136: Custom methods
Keep reading
Related posts
Building software
WebSocket vs SSE vs polling: how each works and when to use it
Polling sends a new request each round, SSE holds one response open for server events, WebSocket upgrades to two-way frames. Reconnects, proxies and firewalls.
Intermediate9 min read
- WebSocket
- Server-Sent Events
- SSE
- Long Polling
- HTTP
- Reverse Proxy
- nginx
Building software
How do offline-first apps keep working without a connection?
Offline-first apps write to a local database first and sync through a queue. One save step by step, plus retries and conflicts, from Android, Flutter and MDN.
Intermediate9 min read
- offline-first
- sync
- IndexedDB
- Service Worker
- WorkManager
- Flutter
- HTTP
Building software
How do HTTP/1.1, HTTP/2 and HTTP/3 differ?
All three share the semantics in RFC 9110. HTTP/1.1 sends text over TCP, HTTP/2 sends binary frames over one TCP connection, HTTP/3 runs on QUIC over UDP.
Intermediate9 min read
- HTTP
- HTTP/2
- HTTP/3
- QUIC
- TCP
- TLS
- Firewalls