Vasu Patel logoVasu Patel
← Designing at Scale: System Design
All chapters in this track
  1. 01Chapter 1: Why System Design Is Its Own Skill
  2. 02Chapter 2: Core Building Blocks and Vocabulary
  3. 03Chapter 3: Eliciting Non-Functional Requirements
  4. 04Chapter 4: Back-of-Envelope Capacity Estimation
  5. 05Chapter 5: Caching Strategies and Cache Invalidation at the Systems Level
  6. 06Chapter 6: Load Balancing and Horizontal Scaling
  7. 07Chapter 7: Database Selection, Replication, and Sharding at a Systems Level
  8. 08Chapter 8: Asynchronous Processing, Message Queues, and Event-Driven Design
  9. 09Chapter 9: API Design from a Systems Perspective: REST, gRPC, GraphQL
  10. 10Chapter 10: The CAP Theorem and Consistency Models in Practical Terms
  11. 11Chapter 11: Microservices vs. Monoliths and Drawing Service Boundaries
  12. 12Chapter 12: Designing for Failure: Redundancy, Failover, Graceful Degradation
  13. 13Chapter 13: A Repeatable Framework for Any System Design Problem
  14. 14Chapter 14: Worked Example: URL Shortener
  15. 15Chapter 15: Worked Example: Chat System
  16. 16Chapter 16: Worked Example: News Feed
  17. 17Chapter 17: Worked Example: Rate Limiter

Chapter 9 of 17

Chapter 9: API Design from a Systems Perspective: REST, gRPC, GraphQL

Why this matters

The companion Networking book's Chapter 10 covered REST, gRPC, and GraphQL from a networking angle — what's on the wire, and why it matters for payload size and round trips. This chapter's job is the systems-design question sitting one level up: given a whole system's architecture (which parts are public-facing, which are internal service-to-service, how many different client types need to consume it), which protocol fits where in that architecture, and why might a single system legitimately use more than one.

Matching protocol choice to position in the architecture

[SENIOR INSIGHT] The single most useful systems-design heuristic from this comparison: REST or GraphQL for public-facing, browser-consumed APIs; gRPC for internal, service-to-service communication — directly following from the Networking book's point that gRPC's browser support is historically weaker while its performance/streaming benefits matter most specifically where you control both ends of the connection (your own internal services).

+------------------+
|   Public Client  |  (browser, mobile app)
+------------------+
         |  REST or GraphQL (browser-friendly, cacheable via standard HTTP)
         v
+------------------+
|   API Gateway    |  (single public entry point -- see below)
+------------------+
         |  gRPC (internal, both ends controlled, performance-sensitive)
         v
+------------------+     +------------------+     +------------------+
|   Service A      | <-> |   Service B      | <-> |   Service C      |
+------------------+     +------------------+     +------------------+
      (internal service-to-service communication, gRPC throughout)

This is a direct, concrete instance of Chapter 7's polyglot-persistence-style reasoning, applied to API protocols instead of databases: no single protocol is uniformly "best" for an entire system — the right choice depends on where in the architecture a specific communication happens and who's on each end of it.

The API Gateway pattern: one public entry point for many internal services

[BEGINNER] In a system with multiple internal services (Chapter 11 covers when this decomposition is warranted), an API Gateway sits between public clients and the internal service mesh, providing a single, unified entry point that handles cross-cutting concerns (authentication, rate limiting — Chapter 17's dedicated worked example, request routing to the correct internal service) so that individual internal services don't each need to reimplement these concerns independently, and so public clients don't need to know the internal architecture's specific service boundaries at all.

Public client request: GET /api/orders/123

API Gateway:
  1. Authenticates the request (shared, centralized logic)
  2. Applies rate limiting (Chapter 17)
  3. Routes to the correct internal service (Order Service) based on the path
  4. Potentially aggregates responses from MULTIPLE internal services into
     one response, if the public API's shape doesn't map 1:1 to internal
     service boundaries

Why GraphQL specifically fits a gateway-aggregation role well

[IN PRACTICE] Directly extending the Networking book's Chapter 10 point about GraphQL letting a client specify exactly what it needs: this fits an API Gateway's aggregation role particularly well in a microservices system (Chapter 11), where a single public-facing query might need data assembled from several different internal services — GraphQL lets the gateway present one unified schema to public clients, resolving each field by internally calling whichever service actually owns that data, hiding the internal service decomposition from clients that shouldn't need to know or care about it.

API versioning: a systems-level compatibility concern

[BEGINNER] As a system evolves, its public API needs to change — and a systems design conversation should address explicitly how backward compatibility is maintained for existing clients that can't all update simultaneously (directly the same rolling-deployment compatibility concern the companion Database book's Chapter 13 covers for schema changes, applied to API contracts specifically):

Versioning via URL path: /api/v1/orders, /api/v2/orders (old and new
versions coexist during a migration window)

Versioning via header: Accept: application/vnd.company.v2+json

Either approach lets existing clients keep working against v1 while new
clients (or clients that have upgraded) use v2 -- directly the same
expand-contract discipline (companion Database book, Chapter 13) applied
to API contracts: never force every client to update simultaneously.

Common mistakes

  1. Choosing one protocol for an entire system's communication uniformly, missing that public-facing and internal service-to-service communication typically have genuinely different requirements (browser compatibility vs. raw performance) that favor different protocols.
  2. Not using an API Gateway in a multi-service system, forcing public clients to know internal service boundaries directly, and forcing each individual service to reimplement cross-cutting concerns like authentication independently.
  3. Making a breaking API change without a versioning strategy, breaking existing clients that can't all update simultaneously — directly the API-level analog of the database schema migration mistakes the companion Database book's Chapter 13 covers.
  4. Using GraphQL's aggregation power without recognizing its systems-level fit specifically for gateway/microservices-aggregation scenarios — applying it reflexively rather than because the system's actual shape (multiple internal services, a need to present one unified public schema) genuinely calls for it.

Discussion / interview questions

  1. "In a system with a public-facing API and multiple internal microservices, which protocol would you use where, and why?" Strong answer: REST or GraphQL for the public-facing API (browser-friendly, cacheable), gRPC for internal service-to-service communication (both ends controlled, performance/streaming benefits matter more where browser compatibility isn't a concern) — a direct, systems-level application of matching protocol to its position in the architecture.

  2. "What is an API Gateway, and what problems does it solve in a multi-service system?" Strong answer: A single public entry point handling cross-cutting concerns (authentication, rate limiting, routing) centrally, so individual internal services don't each reimplement them, and so public clients don't need to know the internal service decomposition — it can also aggregate responses from multiple internal services into one unified public response.

  3. "Why might GraphQL fit particularly well as the protocol an API Gateway presents to public clients in a microservices system?" Strong answer: GraphQL lets a client specify exactly what data it needs across what might be several different internal services' data, letting the gateway present one unified schema and resolve each field by internally calling the appropriate service — hiding the internal decomposition from clients while still assembling a genuinely cross-service response efficiently.

  4. "How would you handle a breaking change to a public API that many existing clients depend on?" Strong answer: Version the API (via URL path or header) so old and new versions coexist during a migration window, letting existing clients continue working against the old version while new/updated clients use the new one — directly the same expand-contract, never-force-simultaneous-update discipline as safe database schema migrations.

Chapter summary / cheat sheet

  • Match API protocol to its position in the architecture: REST/GraphQL for public-facing, browser-consumed APIs; gRPC for internal, service-to-service communication where both ends are controlled and performance matters more.
  • An API Gateway provides one public entry point handling cross-cutting concerns (auth, rate limiting, routing) centrally, and can aggregate multiple internal services' data into one unified response.
  • GraphQL fits a gateway/aggregation role particularly well in microservices systems, letting a unified public schema hide internal service decomposition from clients.
  • API versioning (URL path or header) maintains backward compatibility during a migration window — the API-level analog of safe, expand-contract database schema evolution.