When I first started learning about Architectual styles, I always had a question to the one I discovered:
Why do we need another way to build APIs?
If REST already allows a client to request data, and gRPC allows one service to call another service with high performance, and low latency, what problem is GraphQL actually solving?
The answer becomes clearer when we stop thinking about GraphQL as simply "another REST alternative" too.
GraphQL is mainly about giving the client more control over the data it requests.
Imagine an book store application. A book page might need the name, price, cover image, category, reviews, and information about the author.
With a traditional REST API, you might have:
GET /api/books/111
and the server decides what the response looks like:
{
"id": 111,
"name": "GraphQl from Scratch",
"price": 1200,
"image": "book.jpg",
"category": "developer technology",
"description": "...",
"stock": 42,
"createdAt": "...",
"updatedAt": "..."
}
But perhaps your mobile application only needs:
name
price
image
The API still sends everything else.
Or perhaps the page needs information from several resources:
Book
├── Category
├── Reviews
└── Author
The client might have to make several requests to retrieve everything it needs.
This is one of the problems GraphQL tries to address.
Instead of the server deciding exactly which fields to return, the client can describe the data it needs.
For example:
query {
book(id: 111) {
name
price
image
}
}
The server can then return:
{
"data": {
"book": {
"name": "GraphQl from Scratch",
"price": 1200,
"image": "book.jpg"
}
}
}
The client asked for three fields, and the response contains those three fields.
That is the central idea behind GraphQL.
So, what exactly is GraphQL?
GraphQL is a query language for APIs and a runtime for executing those queries.
It was originally developed at Facebook and later open-sourced.
The important word here is "query."
With REST, the API generally defines endpoints such as:
GET /books/111
GET /books/111/reviews
GET /books/111/author
With GraphQL, you generally have a single endpoint:
POST /graphql
The client sends a query describing the data it wants.
For example:
query {
book(id: 111) {
name
price
reviews {
rating
comment
}
}
}
GraphQL then executes that query against the server's data sources and returns the requested shape.
So instead of thinking:
"Which URL should I call?"
you start thinking:
"What data do I need?"
That is a major difference in the way the API is consumed.
REST vs GraphQL
Let's imagine we're building a food delivery application.
A restaurant has:
Restaurant
├── name
├── address
├── openingHours
├── menu
│ ├── name
│ ├── price
│ └── ingredients
└── reviews
├── rating
└── comment
A REST API could expose:
GET /restaurants/42
Then:
GET /restaurants/42/menu
and:
GET /restaurants/42/reviews
The client may need three requests.
GraphQL could instead allow the client to ask for everything it needs:
query {
restaurant(id: 42) {
name
address
menu {
name
price
}
reviews {
rating
comment
}
}
}
One request can describe the entire data structure needed by the screen.
This doesn't mean GraphQL magically makes everything one database query. The server still has to retrieve the data. It simply gives the client a more flexible way to describe its requirements.
But where does GraphQL get its data?
GraphQL is not a database.
It doesn't replace SQL Server, PostgreSQL, MongoDB, or your existing services.
Think of GraphQL as a layer between the client and your underlying data sources.
For example:
![2222]()
Your GraphQL server might retrieve information from:
SQL Server
PostgreSQL
REST APIs
gRPC services
Other microservices
External APIs
The GraphQL Schema
One of the most important concepts in GraphQL is the schema.
The schema describes what the API can provide.
For example:
type Book {
id: ID!
name: String!
price: Float!
description: String
}
type Query {
book(id: ID!): Book
}
This tells us that the API provides a Product type.
A product has the following properties: id, name, price, description
And the API provides a query called: product
which accepts an ID.
The schema therefore acts as a contract between the client and the server. Like the .proto file in gRPC that we discussed in previous article.
Query, Mutation and Subscription
GraphQL has three major operation types.
Query:
Queries are used to retrieve data.
query {
book(id: 111) {
name
price
}
}
This is conceptually similar to retrieving data with:
GET /api/products/123
Mutation
Mutations are used when we want to change data.
For example:
mutation {
createBook(
name: "GraphQl from Scratch"
price: 1200
) {
id
name
price
}
}
This could create a product.
Subscription
Subscriptions are designed for receiving updates when something happens on the server.
For example, imagine an application that displays the status of an order:
Order placed ---> Preparing ---> Out for delivery ---> Delivered
A subscription could allow the client to receive updates when the order status changes.
subscription {
orderStatusChanged(orderId: 123) {
status
}
}
What makes GraphQL different from REST?
One of the biggest differences is who controls the response shape.
With REST:
--- GET /products/123 --->
Client Server
<--predefined response--
The server largely determines the representation.
With GraphQL:
--- "I need name and price" --->
Client Server
<---resolves requested fields---
The client describes the shape of the response.
This can help solve two common problems.
Over-fetching
Suppose your REST endpoint returns:
{
"id": 123,
"name": "Laptop",
"description": "...",
"price": 1200,
"manufacturer": "...",
"stock": 42,
"createdAt": "...",
"updatedAt": "..."
}
But the UI only needs:
name
price
The client receives information it doesn't need.
GraphQL allows:
query {
product(id: 123) {
name
price
}
}
The response can contain only those fields.
Under-fetching
The opposite problem can happen when one REST endpoint doesn't provide enough information.
For example:
GET /products/123
returns the product.
Then:
GET /products/123/reviews
returns the reviews.
Then:
GET /products/123/seller
returns the seller.
The client needs multiple requests to build one screen.
GraphQL can represent these relationships in one query:
query {
product(id: 123) {
name
price
seller {
name
}
reviews {
rating
}
}
}
When would I choose GraphQL?
GraphQL becomes particularly interesting when the client needs flexibility.
GraphQL allows each client to request the fields it needs.
This is one reason GraphQL is particularly popular for frontend-heavy applications.
⚠️ But GraphQL has its own problems
GraphQL isn't automatically better or faster.
In fact, one of the first problems you can encounter is surprisingly related to a database problem many .NET developers already know: the N+1 query problem.
Imagine:
query {
products {
name
reviews {
rating
}
}
}
You have 1,000 products.
A poorly implemented resolver might execute:
That's the N+1 problem.
GraphQL gives the client a lot of power, so the server needs to control that power.
Imagine allowing a client to request:
product {
relatedProducts {
relatedProducts {
relatedProducts {
relatedProducts {
...
}
}
}
}
}
Without limits, a malicious or simply badly designed query could become extremely expensive.
REST vs GraphQL vs gRPC
A small comparation before we roll wrap this up for the different architectural designs we know
| REST | GraphQL | gRPC |
|---|
| Typical transport | HTTP | HTTP | HTTP/2 |
| Data format | Often JSON | Usually JSON | Protobuf |
| Streaming | Possible, but not its main model | Subscriptions | Strong support |
| Browser usage | Excellent | Excellent | Usually requires gRPC-Web |
| Service-to-service | Very common | Possible | Excellent |
| Strong contract | OpenAPI can provide one | Schema | .proto |