When designing a backend, one of the first decisions is choosing an API style: REST, mature and widespread, or GraphQL, newer and more flexible. Both are capable, but they suit different needs. This article breaks down how each works, the over-fetching problem, their pros and cons, and gives an honest recommendation for typical Laravel projects.
How REST Works
REST (Representational State Transfer) organizes the API around resources (such as products or users), each with its own URL. Actions are determined by the HTTP method: GET reads, POST creates, PUT/PATCH updates, DELETE removes. In Laravel, a single line produces all the endpoints:
// routes/api.php
Route::apiResource('products', ProductController::class);
To fetch a single product, the client calls:
GET /api/products/15
// Response
{
"id": 15,
"name": "Mechanical Keyboard",
"price": 450000,
"stock": 20,
"description": "...",
"created_at": "2026-09-01"
}
Each endpoint returns a fixed structure defined by the server. Simple, easy to cache over HTTP, and familiar to almost every developer.
How GraphQL Works
GraphQL uses a single endpoint (usually /graphql). The client sends a query describing exactly what data it wants, and the server returns precisely that — no more, no less. A query fetching a product but only its name and price:
query {
product(id: 15) {
name
price
}
}
// Response
{
"data": {
"product": {
"name": "Mechanical Keyboard",
"price": 450000
}
}
}
The client can also pull nested relations in a single request — for example a product with its category and reviews — without separate endpoints. In Laravel, GraphQL is typically added via a package such as rebing/graphql-laravel or lighthouse-php.
The Over-fetching and Under-fetching Problem
This is the heart of the difference:
- Over-fetching: in REST, the
/products/15endpoint always returns every column even when a mobile app only needs the name and price. The extra data wastes bandwidth. - Under-fetching: if a screen needs product + category + reviews, in REST you may have to call three separate endpoints (3 round-trips). GraphQL solves it in a single query.
GraphQL eliminates both problems by design because the client dictates the data shape. That said, REST can reduce over-fetching with API Resources or a ?fields= parameter, and under-fetching with combined endpoints (e.g. ?include=category,reviews). Keep in mind that chasing these solutions in REST means you gradually add the very complexity GraphQL gives you for free from the start. So the decision often depends on how varied your clients' needs are: if you have a single client type with fixed needs, mild over-fetching is usually harmless and REST stays simpler.
Pros and Cons
REST
- Pros: simple, HTTP-standard, easy caching (CDN, browser, ETag), broad tooling support, ideal for CRUD.
- Cons: prone to over/under-fetching, endpoint count grows with complexity, versioning (
/v1,/v2) can be cumbersome.
GraphQL
- Pros: clients fetch exactly what they need, one request for nested data, a strong schema with types and auto-generated docs, no explicit versioning needed.
- Cons: HTTP caching is trickier (mostly POST), susceptible to expensive/deep queries that strain the server (needs depth limiting), a steeper learning curve, and the risk of N+1 queries if resolvers are not optimized.
A Real Comparison
Imagine a mobile dashboard screen showing a product's name, price, and its category name. With unoptimized REST:
GET /api/products/15 // fetch product (many unused columns)
GET /api/categories/3 // fetch the category separately
With GraphQL, a single query fetches exactly the three fields:
query {
product(id: 15) {
name
price
category { name }
}
}
For nested data and diverse clients (web, iOS, Android each needing different fields), GraphQL's advantage becomes clear. Conversely, for an endpoint accessed by many people with data that rarely changes — say a public product list — REST can leverage CDN caching and ETag headers so responses are served without ever touching the server. That is a performance edge GraphQL struggles to match, since most GraphQL queries are sent over POST which standard HTTP infrastructure does not cache by default.
When to Choose Each
Choose REST when:
- Your app is mostly simple CRUD (marketplace, blog, admin panel).
- HTTP caching and a CDN matter for performance.
- The team is relatively new and wants to be productive fast — REST + Sanctum in Laravel is very quick to build.
Choose GraphQL when:
- You have many client types with very different data needs.
- Your data is deeply related and you want to avoid dozens of endpoints.
- The frontend needs to iterate fast without always waiting on backend changes.
Verdict for Typical Laravel Projects
For most Laravel projects — especially business apps, marketplaces, and internal systems — REST remains the right default choice. The Laravel ecosystem (resource controllers, API Resources, Sanctum) makes REST fast to build, easy to cache, and easy for the team to understand. GraphQL makes sense when you face many clients with varied data needs or a complex data graph. You can even combine them: REST for the main endpoints, GraphQL for specific complex areas. The key is not which is "better" in the absolute, but which best fits your data's shape and your app's consumption patterns.