In the world of modern web and mobile application development, data fetching and API design play a vital role. For years, REST (Representational State Transfer) has been the dominant architecture for building APIs. However, the emergence of GraphQL, developed by Facebook in 2015, has offered developers a new, more flexible approach to handling data requests.

Both technologies have their strengths and weaknesses, and the choice between them depends on project requirements, scalability needs, and developer preferences. This article explores the differences, similarities, advantages, and drawbacks of GraphQL and REST APIs — supported with coding examples — and concludes with insights on when to use each.

Understanding REST API

REST is an architectural style that defines a set of constraints for creating web services. REST APIs use standard HTTP methods such as GET, POST, PUT, and DELETE to perform CRUD (Create, Read, Update, Delete) operations on resources.

Each piece of data in a RESTful service is represented as a resource and is accessible via a unique URL endpoint. The server sends data in formats like JSON or XML, depending on the client’s request.

Example of a REST API Endpoint

Let’s assume we have a simple API for managing users.

1. Fetching All Users (GET request)

// GET /api/users
fetch('https://example.com/api/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));

Server response (JSON):

[
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
]

2. Fetching a Single User

// GET /api/users/1
fetch('https://example.com/api/users/1')
.then(response => response.json())
.then(user => console.log(user));

Response:

{ "id": 1, "name": "Alice", "email": "alice@example.com" }

3. Creating a New User (POST request)

fetch('https://example.com/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Charlie', email: 'charlie@example.com' })
})
.then(response => response.json())
.then(data => console.log(data));

In REST, each endpoint represents a fixed data structure, and if a client needs additional or fewer fields, a new endpoint or query parameter is often required.

Understanding GraphQL

GraphQL is a query language for APIs and a runtime for executing those queries. It allows clients to request exactly the data they need — no more, no less.

Instead of having multiple endpoints for different data sets (as in REST), GraphQL exposes a single endpoint, and the client specifies the data requirements in a query.

Example of a GraphQL Query

Let’s consider the same use case — fetching user data.

1. Fetching Specific User Fields

query {
users {
id
name
}
}

Response:

{
"data": {
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
}

Notice that the response includes only the requested fields — no unnecessary data such as email or address.

2. Fetching Nested Data

If each user has posts, you can fetch both users and their posts in a single request:

query {
users {
name
posts {
title
content
}
}
}

Response:

{
"data": {
"users": [
{
"name": "Alice",
"posts": [
{ "title": "GraphQL Basics", "content": "Introduction to GraphQL..." }
]
}
]
}
}

In REST, this would typically require multiple requests (one to /users and another to /users/:id/posts), but in GraphQL, it’s handled in one query.

Key Differences Between GraphQL and REST

1. Data Fetching

  • REST: Each endpoint returns a fixed data structure, leading to over-fetching (too much data) or under-fetching (too little data).

  • GraphQL: The client defines exactly what data it needs, eliminating over-fetching and under-fetching issues.

2. Number of Endpoints

  • REST: Multiple endpoints (/users, /posts, /comments, etc.) are used for different resources.

  • GraphQL: A single endpoint (/graphql) serves all queries and mutations.

3. Versioning

  • REST: Often requires versioning (e.g., /v1/users, /v2/users) when changing the API structure.

  • GraphQL: Versioning is generally unnecessary because clients can request only the fields they need, and new fields can be added without breaking existing queries.

4. Performance and Network Usage

  • REST: May require multiple network calls to fetch related data (e.g., a user and their posts).

  • GraphQL: Can fetch related data in a single request, improving performance for complex queries.

5. Error Handling

  • REST: Relies on HTTP status codes (404, 500, etc.) for error representation.

  • GraphQL: Always returns a 200 OK response with an errors field in the JSON response when something goes wrong.

Example:

{
"data": null,
"errors": [{ "message": "User not found" }]
}

6. Caching

  • REST: Easier to cache using HTTP caching mechanisms (like ETag, Last-Modified).

  • GraphQL: Caching is more complex because queries can vary dynamically; however, libraries like Apollo Client provide sophisticated caching strategies.

7. File Uploads and Subscriptions

  • REST: Handles file uploads via multipart/form-data; real-time updates often use WebSockets separately.

  • GraphQL: Supports both file uploads (via mutations) and real-time data through subscriptions in a unified structure.

Practical Implementation Example

To illustrate the practical differences, let’s explore both REST and GraphQL implementations for the same use case — fetching user data with posts.

REST Implementation (Node.js and Express)

const express = require('express');
const app = express();
app.use(express.json());
const users = [
{ id: 1, name: ‘Alice’, posts: [{ title: ‘REST vs GraphQL’ }] },
{ id: 2, name: ‘Bob’, posts: [{ title: ‘Understanding APIs’ }] },
];app.get(‘/users’, (req, res) => {
res.json(users);
});app.get(‘/users/:id’, (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
user ? res.json(user) : res.status(404).send(‘User not found’);
});app.listen(4000, () => console.log(‘REST API running on port 4000’));

Here, to get both a user and their posts, you’d typically make two separate calls or structure the server to return nested data.

GraphQL Implementation (Node.js with Express and GraphQL)

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
const schema = buildSchema(`
type Post {
title: String
}
type User {
id: ID
name: String
posts: [Post]
}
type Query {
users: [User]
user(id: ID!): User
}
`
);const users = [
{ id: 1, name: ‘Alice’, posts: [{ title: ‘REST vs GraphQL’ }] },
{ id: 2, name: ‘Bob’, posts: [{ title: ‘Understanding APIs’ }] },
];const root = {
users: () => users,
user: ({ id }) => users.find(u => u.id === parseInt(id)),
};const app = express();
app.use(‘/graphql’, graphqlHTTP({ schema, rootValue: root, graphiql: true }));
app.listen(4000, () => console.log(‘GraphQL API running on port 4000’));

In this example, clients can request only the data they need using queries, without requiring additional endpoints or backend logic changes.

Advantages and Disadvantages

Advantages of REST

  • Simplicity and ease of implementation

  • Broad adoption and tooling support

  • Works seamlessly with HTTP caching

  • Predictable resource-based endpoints

Disadvantages of REST

  • Over-fetching and under-fetching problems

  • Requires multiple requests for complex data

  • Versioning can become difficult to maintain

Advantages of GraphQL

  • Single endpoint for all data fetching

  • Prevents over-fetching and under-fetching

  • Strongly typed schema and introspection support

  • Better suited for complex and nested data structures

  • Simplifies API evolution without versioning

Disadvantages of GraphQL

  • More complex server setup

  • Caching can be challenging

  • Potential for inefficient queries if not optimized

  • Steeper learning curve for beginners

When to Use REST or GraphQL

  • Use REST when:

    • Your API is simple and resource-based.

    • You rely heavily on HTTP caching.

    • You have predictable data structures.

    • You want wide compatibility and simplicity.

  • Use GraphQL when:

    • Your frontend requires dynamic or nested data.

    • You want to minimize network requests.

    • You’re building a data-rich or mobile-first application.

    • You need flexibility for rapid API evolution.

Conclusion

Both GraphQL and REST serve the same purpose — facilitating communication between clients and servers — but they approach the problem differently.

REST emphasizes simplicity and established conventions, making it ideal for straightforward, resource-based APIs where caching and scalability are crucial.

GraphQL, on the other hand, revolutionizes data fetching by allowing clients to request exactly what they need through a single endpoint. It excels in complex applications, especially where performance, flexibility, and nested data retrieval are essential.

Ultimately, there is no universal “better” choice. The decision depends on your project’s needs. REST remains a solid, time-tested standard, while GraphQL offers a modern, efficient, and flexible alternative for the data-driven web of today. Many modern systems even combine both — using REST for simple endpoints and GraphQL for complex queries — leveraging the strengths of each to build robust, efficient APIs.