Course → Module 1: Architectural Foundations & Core Concepts

Two Approaches to API Communication

Once a client and server can communicate over HTTP (Session 1.1 and 1.2), the next question is: how should they structure that communication? What format should the request take? How should the server expose its data and operations?

This is the domain of API protocols. Two dominate modern system design: REST and GraphQL. They solve the same fundamental problem, allowing a client to read and write data on a server, but they make very different design choices about how to do it.

REST: Representational State Transfer

REST is not a protocol. It is an architectural style, defined by Roy Fielding in his 2000 doctoral dissertation. Fielding was one of the principal authors of the HTTP specification, and REST describes the design principles that made HTTP successful.

REST is built on six constraints. Four of them form the uniform interface, which is the defining feature of REST:

REST Uniform Interface: (1) Resources are identified by URIs. (2) Resources are manipulated through representations (JSON, XML, HTML). (3) Messages are self-descriptive, containing all information needed to process them. (4) Hypermedia drives application state (HATEOAS), meaning the server's responses include links to related resources and available actions.

In practice, most REST APIs follow a predictable pattern. Resources map to URL paths. HTTP methods map to operations.

HTTP Method Operation Example Idempotent?
GET Read GET /users/42 Yes
POST Create POST /users No
PUT Replace PUT /users/42 Yes
PATCH Partial update PATCH /users/42 No (by convention)
DELETE Delete DELETE /users/42 Yes

REST inherits HTTP's statelessness. Each request must contain all the information the server needs. No session context is assumed. This makes REST APIs easy to cache (GET responses can be cached by any HTTP cache), easy to scale (any server can handle any request), and easy to reason about (each endpoint has a clear, predictable behavior).

The Over-Fetching and Under-Fetching Problem

REST's simplicity comes with a cost. Each endpoint returns a fixed data structure. If you request GET /users/42, you get the entire user object: name, email, avatar, bio, preferences, creation date, and every other field. If you only needed the name and avatar, you still receive everything else. This is over-fetching.

Conversely, if you need a user's profile along with their 5 most recent posts and each post's comment count, you might need three separate requests: one for the user, one for the posts, one for the comment counts. This is under-fetching, and it means multiple round trips, each adding latency.

On a desktop with a fast connection, this is tolerable. On a mobile device over a cellular network, where each round trip adds 100-300ms of latency, it becomes a real performance problem.

GraphQL: Query What You Need

GraphQL was developed at Facebook in 2012 and open-sourced in 2015. The GraphQL specification describes it as a query language for APIs and a runtime for executing those queries against your data.

The core idea: the client specifies exactly what data it needs, and the server returns exactly that. No more, no less.

A GraphQL API exposes a single endpoint (typically POST /graphql). Instead of choosing between many endpoints, the client sends a query that describes the shape of the data it wants:

# GraphQL query
{
  user(id: 42) {
    name
    avatar
    posts(limit: 5) {
      title
      commentCount
    }
  }
}

This single request replaces the three REST calls from the previous example. The server returns a JSON response that mirrors the query structure exactly:

{
  "data": {
    "user": {
      "name": "Alice",
      "avatar": "/images/alice.jpg",
      "posts": [
        { "title": "On Feedback Loops", "commentCount": 12 },
        { "title": "Scaling Lessons", "commentCount": 7 }
      ]
    }
  }
}

GraphQL: A query language for APIs where the client defines the structure of the response. Uses a strongly-typed schema to describe available data. All requests go to a single endpoint. Eliminates over-fetching and under-fetching by letting clients request exactly the fields they need.

REST vs. GraphQL: A Comparison

sequenceDiagram participant C as Client participant R as REST API participant G as GraphQL API Note over C,R: REST: Multiple endpoints C->>R: GET /users/42 R-->>C: Full user object (all fields) C->>R: GET /users/42/posts?limit=5 R-->>C: Posts array (all fields per post) C->>R: GET /posts/101/comments/count R-->>C: Comment count Note over C,G: GraphQL: Single endpoint C->>G: POST /graphql (query with exact fields) G-->>C: Only requested fields, nested
Dimension REST GraphQL
Endpoints Multiple (one per resource) Single (/graphql)
Data fetching Server decides what to return Client decides what to return
Over-fetching Common (fixed response shapes) Eliminated (client specifies fields)
Under-fetching Common (multiple round trips) Eliminated (nested queries in one request)
Caching Straightforward (HTTP caching by URL) Complex (all requests hit same URL with POST)
Versioning Typically URL-based (/v1/, /v2/) Schema evolution (add fields, deprecate old ones)
Type system None built-in (OpenAPI/Swagger is optional) Strongly typed schema (required)
Error handling HTTP status codes Always returns 200; errors in response body
Learning curve Low (uses standard HTTP conventions) Higher (new query language, schema design)
Best suited for Simple CRUD, public APIs, resource-oriented services Complex data relationships, mobile clients, varied consumer needs

When REST Shines

REST is the better choice when your data model is simple and resource-oriented. If your API mostly serves CRUD operations (create, read, update, delete) on well-defined entities, REST's predictable URL structure and HTTP caching are hard to beat. Public APIs favor REST because it is universally understood, requires no specialized client libraries, and works with any HTTP client.

REST also excels when caching matters. Because each resource has its own URL, HTTP caches (browsers, CDNs, reverse proxies) can cache responses efficiently. A GET /users/42 response can be cached and reused by any client requesting the same resource.

When GraphQL Shines

GraphQL is the better choice when clients have diverse data needs. A mobile app might need a compact subset of user data. A desktop dashboard might need the full object with related entities. A third-party integration might need a completely different combination. With REST, you either build custom endpoints for each consumer or force everyone to over-fetch.

GraphQL also wins when the data model is deeply relational. If fetching a page requires combining data from users, posts, comments, reactions, and notifications, a single GraphQL query can traverse those relationships in one round trip. The equivalent REST implementation would require either multiple sequential requests or a custom aggregate endpoint.

The Trade-Off in Systems Terms

From a systems thinking perspective, REST and GraphQL shift complexity to different parts of the system. REST puts complexity on the client (which must orchestrate multiple requests and handle over-fetched data). GraphQL puts complexity on the server (which must resolve arbitrary query shapes and protect against expensive queries). Neither eliminates complexity. They relocate it.

This is a recurring theme in system design: there is no free lunch. Every architectural choice is a transfer of burden from one component to another. The skill is in choosing which component is best equipped to handle that burden given your specific constraints.

Further Reading

Assignment

You are building a mobile app for a social platform. The user profile screen shows:

  • User name and avatar
  • Bio (optional, only 40% of users have one)
  • Follower count
  • 5 most recent posts (title and timestamp only)

Answer these questions:

  1. If you use a REST API, how many requests would the client need to make? What data would be over-fetched?
  2. If you use GraphQL, write the query (or describe its structure) that would fetch this screen's data in a single request.
  3. Which protocol would reduce bandwidth usage for this mobile client, and why?

Consider: the mobile app is used on cellular networks where every kilobyte and every round trip counts. Your choice should reflect that constraint.