Menu
Course/Networking & Communication/API Design: REST, GraphQL & gRPC

API Design: REST, GraphQL & gRPC

Compare REST, GraphQL, and gRPC: when to use each, versioning strategies, pagination, and API design best practices.

18 min readHigh interview weight

The Three Major API Paradigms

Modern distributed systems communicate primarily through APIs. Three paradigms dominate: REST (the web's default), GraphQL (flexible client-driven queries), and gRPC (high-performance binary RPC). Each reflects different trade-offs between simplicity, flexibility, and performance.

AspectRESTGraphQLgRPC
ProtocolHTTP/1.1 or HTTP/2HTTP/1.1 or HTTP/2HTTP/2
Data formatJSON (usually), XMLJSONProtocol Buffers (binary)
SchemaOpenAPI / informalStrongly typed GraphQL schemaStrongly typed .proto files
FetchingFixed endpoints, may over/under-fetchClient requests exactly what it needsFixed RPC methods in proto
Real-timePolling or webhooksSubscriptions (WebSocket)Server streaming, bidirectional streaming
Tooling maturityExcellent — universal supportGood — Apollo, RelayGood — generated stubs in 10+ languages
Browser supportNativeNativeRequires gRPC-Web proxy
Best forPublic APIs, simple CRUD, external clientsFlexible client needs, multiple client types (mobile/web)Internal microservices, low-latency, streaming

REST: Representational State Transfer

REST is an architectural style built on HTTP conventions. Resources are identified by URLs, and HTTP verbs (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) represent operations. A well-designed REST API is self-describing, cacheable, and stateless.

http
# Create a user
POST /users
Content-Type: application/json
{"name": "Alice", "email": "alice@example.com"}

# Read a user
GET /users/123

# Update a user (partial)
PATCH /users/123
{"name": "Alice Smith"}

# List a user's orders (nested resource)
GET /users/123/orders?status=pending&page=2&limit=20

# Delete a user
DELETE /users/123
  • Stateless: Each request contains all information needed to process it. No server-side session state.
  • Uniform interface: Consistent URL structure and HTTP verb semantics across all resources.
  • Cacheable: GET responses can be cached. REST's alignment with HTTP makes CDN integration natural.
  • Layered system: Clients don't need to know if they're talking to the server directly or via a proxy.

GraphQL

GraphQL was developed by Facebook to solve the over-fetching and under-fetching problems of REST. Clients send a query describing exactly what data they need, and the server returns precisely that — no more, no less.

graphql
# Client requests exactly the fields it needs
query {
  user(id: "123") {
    name
    email
    orders(status: PENDING) {
      id
      total
      items {
        productName
        quantity
      }
    }
  }
}

# Mutations change data
mutation {
  createUser(input: { name: "Alice", email: "alice@example.com" }) {
    id
    name
  }
}

# Subscriptions for real-time updates
subscription {
  orderStatusChanged(userId: "123") {
    orderId
    newStatus
  }
}
⚠️

GraphQL trade-offs

GraphQL solves over/under-fetching but introduces complexity: N+1 query problems (use DataLoader to batch), cache invalidation is harder (no URL-based caching), and file uploads require workarounds. It also exposes your full data model to clients, which can be a security concern for public APIs. Use GraphQL when you have diverse clients with varying data needs (mobile vs web vs third-party).

gRPC

gRPC (Google Remote Procedure Call) uses Protocol Buffers for serialization and HTTP/2 for transport. It generates client and server stubs in 10+ languages from a `.proto` schema file, making cross-language service communication type-safe and efficient.

protobuf
// users.proto
syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (stream User); // server streaming
  rpc CreateUser (CreateUserRequest) returns (User);
}

message GetUserRequest {
  string user_id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
  int64 created_at = 4;
}

Protocol Buffers produce binary payloads 5-10x smaller than equivalent JSON. HTTP/2 multiplexing allows multiple RPC calls over a single TCP connection. gRPC natively supports four communication patterns: unary (request-response), server streaming, client streaming, and bidirectional streaming.

API Versioning Strategies

APIs must evolve without breaking existing clients. The main versioning strategies are:

StrategyExampleProsCons
URL path versioning`/v1/users`, `/v2/users`Explicit, easy to see in logs and docsURL is supposed to identify a resource, not a version
Query parameter`/users?version=2`Clean URLsEasy to forget, not cacheable cleanly
Header versioning`API-Version: 2`Clean URLs, follows HTTP semanticsHarder to test in browser, less discoverable
Content negotiation`Accept: application/vnd.example.v2+json`Fully RESTfulComplex, poor tooling support
Proto backward compatibilityAdd new fields only; never remove or renumberNo version needed for minor changesSchema discipline required

Pagination Patterns

When APIs return lists, pagination prevents responses from growing unbounded. Three main approaches exist:

PatternHow It WorksUse CaseWeakness
Offset/limit`?page=3&limit=20` → `OFFSET 40 LIMIT 20`Simple, works with any SQL DBPerformance degrades at high offsets; items can shift between pages
Cursor-based`?cursor=<opaque-token>` (encodes last seen ID)Real-time feeds (Twitter, Facebook)Cannot jump to arbitrary pages
Keyset / seek`?after_id=1234&limit=20` → `WHERE id > 1234`High-performance; stable with insertsRequires indexed sort column
💡

Prefer cursor-based pagination for feeds

Offset pagination breaks when new items are inserted — a user refreshing a page sees duplicates or skipped items as rows shift. Cursor-based pagination is stable: the cursor encodes the position in the result set, not a numeric page number. Use offset pagination only for slow-changing data where users need to jump to arbitrary pages.

💡

Interview Tip

In API design interviews, always clarify the client context first: Who are the consumers? Internal microservices (gRPC is great), a mobile app with diverse data needs (GraphQL), or a public third-party API (REST with OpenAPI). Then discuss versioning and pagination. Bonus: mention idempotency keys for mutation safety — any non-idempotent operation (creating an order, charging a card) should accept a client-generated idempotency key so retries don't cause duplicates.

📝

Knowledge Check

5 questions

Test your understanding of this lesson. Score 70% or higher to complete.

Ask about this lesson

Ask anything about API Design: REST, GraphQL & gRPC