API · Rest

REST vs GraphQL vs gRPC — Decision Guide

REST vs GraphQL vs gRPC — Decision Guide is the work that makes the systems talk. The API is the contract between the producer and the consumer; the contract is what determines.

John Kihiu12 min read

REST, GraphQL, and gRPC aren't ranked by quality — they're optimised for different callers and different constraints. Picking one because it's trendy, rather than because it fits how your API will actually be consumed, is how teams end up bolting a GraphQL layer onto a system that only ever needed three well-designed REST endpoints.

REST: the default for a reason

REST's strength is ubiquity — every language has a mature HTTP client, every developer already understands resources and status codes, and HTTP caching (ETags, Cache-Control) works for free at every layer of the stack from browser to CDN to reverse proxy. Its weakness shows up with nested or relational data: a mobile client that needs a user, their last five orders, and each order's line items either makes several round trips or the backend grows a bespoke aggregation endpoint for that one screen — the classic over-fetching/under-fetching problem REST doesn't solve on its own. REST is the right default for public APIs, CRUD-shaped resources, and anywhere HTTP caching semantics genuinely help.

GraphQL: when clients need to drive the response shape

GraphQL solves over-fetching directly — the client specifies exactly which fields it wants across however many related resources, in one request, and the server resolves them. This is a genuine win for frontend teams shipping multiple client types (web, iOS, Android) against one backend, where each client wants a different slice of the same data. The costs are real too: a naive resolver implementation causes the N+1 query problem (fetching a list, then querying once per item for its relations), which needs batching solutions like DataLoader to fix; HTTP caching mostly stops working because everything's a POST to one endpoint; and a single complex query can be an unintentional denial-of-service vector if you don't add query depth and complexity limits.

GRAPHQL · CLIENT-SHAPED QUERY
query OrderSummary($userId: ID!) {
  user(id: $userId) {
    name
    orders(last: 5) {
      id
      total
      lineItems {
        sku
        quantity
      }
    }
  }
}

gRPC: internal service-to-service performance

gRPC uses HTTP/2 and Protocol Buffers instead of JSON over HTTP/1.1, which gives it a real performance edge — binary serialisation is smaller and faster to parse, and HTTP/2 multiplexing avoids head-of-line blocking. It also generates strongly-typed client and server code from a single .proto contract, which is a genuine productivity win for internal microservices maintained by teams who control both ends. The tradeoff: it's a poor fit for public or browser-facing APIs, since browsers can't speak gRPC natively without a proxy layer (grpc-web), and the binary format is opaque to casual debugging with curl in a way JSON never is.

gRPC's real competition is internal REST, not public APIs

The decision to adopt gRPC is almost always about service-to-service traffic inside your own infrastructure, where you control both client and server codegen. It rarely makes sense as the public-facing contract for third-party consumers.

The decision in practice

Public API, third-party consumers, resource-shaped data, want HTTP caching to just work: REST. Multiple client types with genuinely different data needs against a shared backend, frontend team owns the pain of over/under-fetching: GraphQL, with resolver-level batching from day one. Internal service mesh, both ends under your control, latency and throughput matter more than human readability: gRPC. Many real systems run all three at once — REST or GraphQL at the edge for clients, gRPC between internal services — because the decision is per-boundary, not company-wide.

Don't add GraphQL to fix a REST API you designed poorly

Over-fetching is often a symptom of resources that don't match how clients actually use the data, not a fundamental limitation of REST. A well-designed set of purpose-built REST endpoints frequently solves the same problem GraphQL was reached for, with far less operational complexity.

StyleStrongest forWeak point
RESTPublic APIs, HTTP caching, simplicityOver/under-fetching on nested data
GraphQLMultiple clients, client-driven shapeN+1 queries, cache complexity, query cost limits
gRPCInternal service-to-service, performancePoor browser support, opaque wire format

Wrapping up

Choose based on who's calling and what they need from the response shape, not on which style is having a moment. REST remains the sound default for anything public; reach for GraphQL when client-driven shaping earns its resolver complexity, and for gRPC when the calls never leave your own infrastructure.

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.