Acumatica · Rest

REST HATEOAS vs RPC — A Comparison

REST with hypermedia versus RPC-style APIs (gRPC, JSON-RPC) -- the real trade-off is discoverability and HTTP semantics against raw performance and code-generation ergonomics.

John Kihiu12 min read

REST-with-hypermedia and RPC-style APIs solve the same underlying problem — let a client call functionality on a server over a network — from opposite design premises. REST models the world as resources you act on with a small fixed verb set; RPC models it as named procedures you call directly, with whatever inputs and outputs the procedure needs. Neither is universally correct, and the choice matters more at the edges of your system (external partners, mobile clients, high-throughput internal services) than most teams treat it.

What RPC-style APIs buy you

gRPC and JSON-RPC let you call CancelOrder(order_id) as a method, with a strongly-typed request and response defined in a schema (protobuf for gRPC), and client/server stubs generated automatically in whatever language you need. There's no URL design to argue about, no debate over whether an action fits the resource model, and for gRPC specifically, HTTP/2 multiplexing and binary protobuf encoding make it meaningfully faster than JSON-over-HTTP/1.1 for high-throughput internal service-to-service calls. This is the right tool when both ends of the call are systems you control, performance matters, and you want the compiler to catch a mismatched field type before it reaches production.

PROTO · GRPC SERVICE DEFINITION
service OrderService {
  rpc CancelOrder(CancelOrderRequest) returns (Order);
}
message CancelOrderRequest {
  string order_id = 1;
  string reason = 2;
}

What REST buys you back

REST's resource model gives you HTTP's caching semantics for free (a GET is cacheable by any standards-compliant intermediary; an RPC call over POST generally is not, since the semantics live in the body, invisible to caches), a uniform, guessable interface (any HTTP client can call it, no generated stub required), and a natural mapping onto browser-based clients that RPC binary protocols don't have — gRPC in particular needs a proxy layer (grpc-web) to work from a browser at all. REST also ages better for public APIs with consumers you don't control: a JSON-over-HTTP contract can be inspected, tested with curl, and integrated against without installing a code generator.

Hypermedia specifically, versus RPC's schema-first discoverability

Both approaches solve API discoverability, just at different times: RPC discoverability happens at build time, through a shared .proto or OpenAPI/JSON-RPC schema that generates client code — the client knows every available method before it ever makes a call. HATEOAS discoverability happens at runtime, through links embedded in responses — the client learns what's possible as it goes. Build-time discoverability is strictly more convenient for a known, controlled set of clients (better IDE autocomplete, compile-time errors on a renamed field); runtime discoverability is more resilient to server-side changes for clients you don't control and can't force to redeploy.

Internal vs. external is usually the deciding factor

gRPC for internal service-to-service calls where you control both ends and want speed plus type safety; REST (with or without hypermedia) for anything a browser, a third party, or an unknown future client needs to call. Plenty of production systems run both, at different boundaries, rather than picking one philosophy for the entire architecture.

JSON-RPC as a lighter middle ground

JSON-RPC keeps RPC's procedure-call model — a method name and parameters in the request body — but stays in plain JSON over regular HTTP, without gRPC's binary encoding, HTTP/2 requirement, or code-generation toolchain. It's a reasonable choice when you want RPC's directness (skip modeling every action as a resource) but need something a browser or a simple HTTP client can call without special tooling. It gives up REST's caching and uniform-interface benefits just the same as gRPC does, since the semantics still live in the request body rather than the URL and method.

Don't pick gRPC for a public API you expect third parties to integrate against directly

Requiring external partners to install protobuf tooling and generate client stubs is a real integration tax that plain REST or JSON-RPC over HTTP doesn't impose. gRPC's ergonomics are built for teams that own the client and server both — for a partner API, that assumption usually doesn't hold.

Wrapping up

REST and RPC aren't competing on correctness — they're optimized for different constraints. Choose RPC (gRPC or JSON-RPC) when you control both ends and want speed or build-time type safety; choose REST, with hypermedia links where the client population is genuinely unknown, when HTTP-native caching, browser compatibility, and integration without a code generator matter more than raw throughput.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.