TL;DR
GraphQL puts an end to the drama of over-fetching (receiving too much data) and under-fetching (having to make dozens of calls to complete a single view). With a single Query, you request exactly the fields you need. You use Mutations to modify data and Subscriptions for real-time updates—all governed by a strictly typed Schema that acts as a contract between the server and the client. While it introduces some initial complexity with its resolvers, it is the ultimate tool for applications with complex relational data where efficiency and frontend flexibility are the top priorities.
GraphQL
Unlike REST, where the server decides what data to return at each endpoint, GraphQL allows the client to specify exactly which fields it needs. The result: less data transferred, fewer server calls, and a much smoother development experience.
An analogy I really like: REST is like ordering a "meal of the day" where they bring you everything included in the set menu. GraphQL is like ordering a custom order only what you specifically requested arrives at your table.
The Problem GraphQL Solves
Over-fetching
Imagine you have a GET /users/42 endpoint and you only need the user's name to display in an avatar. The REST response returns everything:
{
"id": "42",
"name": "Ana García",
"email": "[email protected]",
"age": 28,
"bio": "Full stack developer...",
"avatar": "https://cdn.example.com/ana.jpg",
"createdAt": "2023-01-15T10:30:00Z"
}
You received 7 fields when you only needed 1. That is over-fetching.
Under-fetching
Now you need to display the user's profile along with their latest posts. With REST, you might need:
GET /users/42→ user dataGET /users/42/posts→ user's posts- Perhaps
GET /posts/8/comments→ comments for the first post
Three requests to the server. That is under-fetching.
The GraphQL Solution
With GraphQL, you make a single request and ask for exactly what you need:
query {
user(id: "42") {
name
avatar
posts {
title
publishedAt
}
}
}
The Three GraphQL Operations
GraphQL has three types of operations that cover everything you need to do with an API.
Query
The most common operation. It is the equivalent of a GET in REST.
query GetUser {
user(id: "42") {
name
email
posts {
title
publishedAt
}
}
}
Mutation
Used to create, edit, or delete data. Equivalent to POST, PUT, PATCH, and DELETE.
mutation CreatePost {
createPost(input: {
title: "My first post with GraphQL"
content: "Today I learned how to use mutations..."
}) {
id
title
createdAt
}
}
Subscription
Used to listen for server events via WebSockets. Perfect for chats, notifications, or live feeds.
subscription NewMessage {
newMessage(chatId: "dev-room") {
text
author
timestamp
}
}
The Schema
Before a client can perform queries, the server defines its schema. This is the contract that describes all available data types and operations.
It is written in SDL (Schema Definition Language):
type User {
id: ID!
name: String!
email: String!
age: Int
posts: [Post!]
}
type Post {
id: ID!
title: String!
content: String!
published: Boolean!
author: User!
}
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createPost(title: String!, content: String!): Post!
}
The ! symbol indicates that the field is mandatory (non-null). If it's not present, the field can be null.
4 Concrete Advantages of GraphQL
- Precision: Request only what you need, eliminating over-fetching and under-fetching.
- Efficiency: A single request for related data, all within one query.
- Safety: Strongly typed data guaranteed by the schema.
- Tooling: Automatic documentation with tools like Apollo Studio.
When NOT to use GraphQL?
If your API is simple, with few resources and a single client, REST might be more than enough. GraphQL adds complexity through schemas and resolvers.
GraphQL wasn't created to replace REST, but to solve specific problems that REST struggles with: bloated data, multiple requests, and APIs serving very diverse clients.
My recommendation is to learn the fundamentals: create a basic schema with Apollo Server, and run your first queries and mutations. You can start with the official documentation, which is very well explained and full of examples: graphql.org/learn/introduction.