What GraphQL Is and Why REST Falls Short
REST limitations at scale, what GraphQL solves, and how the spec actually works
REST works well for simple APIs. But as products grow, REST develops painful patterns: endpoints that return way more data than the client needs, mobile apps making 5 network requests to paint one screen, and backend teams creating new endpoints for every slightly different frontend requirement. GraphQL was designed to solve exactly these problems.
The REST limitations that GraphQL targets
- Over-fetching — A REST endpoint returns a full User object (30 fields) when the UI only needs name and avatar. Every extra field costs bandwidth — on slow mobile connections, this is real latency.
- Under-fetching — To render a profile page with posts and followers, a client makes GET /user, then GET /user/posts, then GET /user/followers. Three round trips. GraphQL collapses these into one.
- Endpoint proliferation — As the product adds features, you end up with /users/summary, /users/full, /users/minimal — variants of the same resource. Every variant needs documentation, versioning, and maintenance.
- Frontend-backend coupling — When the frontend wants different data, it needs a backend deploy. With GraphQL, the frontend describes its exact needs — the backend does not need to change.
The three operation types
- Query — Read data. Equivalent to GET. Queries are the most common operation — "give me this specific data in this specific shape."
- Mutation — Write data. Equivalent to POST/PUT/DELETE. Mutations make changes and return the updated data in a single operation.
- Subscription — Real-time updates over WebSocket. The client subscribes to events (e.g. new messages) and the server pushes updates as they happen.
GraphQL is like a restaurant where you build your own order
With REST, you order from a fixed menu — you get the combo whether you want the fries or not. With GraphQL, you tell the kitchen exactly what you want: "I'll have the burger but skip the bun, add extra tomato, and side of onion rings." The kitchen sends back exactly that — nothing more, nothing less. Your query is the order. The schema is the menu.
How the spec works
GraphQL is a specification, not an implementation. Facebook published the spec in 2015; there are now implementations in every major language (Apollo Server, Yoga, Pothos in JS; Strawberry in Python; gqlgen in Go). The spec defines the query language syntax, type system, execution model, and introspection system. This means GraphQL APIs behave consistently regardless of what server library you use.
A GraphQL query vs the equivalent REST calls
# GraphQL: one request, exactly the shape you need
query GetUserProfile($id: ID!) {
user(id: $id) {
name
avatar
posts(limit: 5) {
title
publishedAt
}
followerCount
}
}
# REST equivalent (3 separate requests):
# GET /users/:id → 30 fields, you use 3
# GET /users/:id/posts → all posts, you show 5
# GET /users/:id/stats → all stats, you use 1Try this
Open the GitHub GraphQL Explorer at api.github.com/graphql and run a query for your own profile: { viewer { login name bio repositories(first: 5) { nodes { name stargazerCount } } } }. Observe that you get exactly the fields you asked for, nothing more.