2 Quick Comparisons: GraphQL vs REST API
2 Quick Comparisons: GraphQL vs REST API
The growth of web and mobile technology has steadily increased the need for data that is efficient and easy to manage. In the world of API development, there are two popular technologies we frequently encounter: REST API and GraphQL. Both offer solutions for transferring data between client and server, but they follow different paradigms.
As an engineer who has spent several years building digital products, I’m often faced with the question: “Should we go with REST API or GraphQL?” This article walks through two key comparisons between GraphQL and REST API using code examples, simulations, and illustrated tables and diagrams. Hopefully it helps you decide which one is the right fit for your project!
1. How You Request and Receive Data
REST API
REST (Representational State Transfer) designs an endpoint for each resource. For example, for the users resource, each action has a different endpoint:
1GET /users // Get data for all users
2GET /users/1 // Get data for the user with id=1
3POST /users // Add a new user
4PUT /users/1 // Update the user with id=1
5DELETE /users/1 // Delete the user with id=1Usually, when the client needs nested data (for example, a user along with all of their posts), the client has to make several requests:
1// Fetch the user
2fetch('/users/1')
3 .then(res => res.json())
4 .then(user => {
5 // Fetch that user's posts
6 fetch(`/users/1/posts`)
7 .then(res => res.json())
8 .then(posts => {
9 // merge the posts into the user object
10 user.posts = posts;
11 console.log(user);
12 });
13 });GraphQL
GraphQL has only a single endpoint (/graphql). The client can decide for itself exactly what data it wants to request, even nested data, all in a single request:
1query {
2 user(id: 1) {
3 id
4 name
5 posts {
6 id
7 title
8 }
9 }
10}The server responds to the request with a data structure that matches exactly what was requested:
1{
2 "data": {
3 "user": {
4 "id": 1,
5 "name": "Budi",
6 "posts": [
7 { "id": 101, "title": "Belajar REST" },
8 { "id": 102, "title": "GraphQL itu Mudah" }
9 ]
10 }
11 }
12}Flow Diagram Simulation
Let’s compare the data request flow with REST and GraphQL using a flow diagram (Mermaid):
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /users/1
Server-->>Client: {id, name}
Client->>Server: GET /users/1/posts
Server-->>Client: [post1, post2, ...]
Note right of Client: Harus dua kali request (REST)
Client->>Server: POST /graphql {user dan posts}
Server-->>Client: {id, name, posts}
Note right of Client: Satu kali request (GraphQL)
Comparison Table
| Feature | REST API | GraphQL |
|---|---|---|
| Endpoint | Many (one per resource/action) | One (/graphql) |
| Response data | All data in the model/endpoint | Only the requested fields |
| Nested resource | Requires several requests | A single query |
| Over-fetching/Under-fetching data | Happens often | Rarely happens |
2. API Versioning and Schema Evolution
REST API
A REST API typically uses a version in the URL, for example /api/v1/users. Every major change (breaking change) usually requires adding a new versioned endpoint so that older clients keep working.
1/api/v1/users
2/api/v2/usersWhen a new attribute is added to a resource (for example, adding username), every client that doesn’t need this field will usually still receive its data (over-fetching).
Advantages
- The API schema is clearly documented.
- Easy to cache via HTTP caching (because the endpoints are fixed).
Disadvantages
- API evolution is slow, and you have to be careful when removing or changing attributes.
- Adding fields can make the response large (over-fetching).
GraphQL
In GraphQL, the endpoint version usually doesn’t need to change, because the query the client sends determines for itself which fields are needed. Backend developers can add new fields at any time without disrupting older clients.
For example, if we add a username field to the User type, an older client that only queries id and name won’t be affected at all.
1// Old query (old client)
2query {
3 user(id: 1) {
4 id
5 name
6 }
7}
8
9// New query (new client)
10query {
11 user(id: 1) {
12 id
13 name
14 username
15 }
16}Advantages
- Schema evolution is more flexible and involves minimal breaking changes.
- No need for a new version for non-breaking changes.
- Documentation and autocompletion come directly from the schema (SDL).
Disadvantages
- Standard HTTP caching (like REST) can’t be used directly.
- Queries can potentially become too deep and heavy if not limited.
API Evolution Comparison
| Concern | REST API | GraphQL |
|---|---|---|
| Schema changes | Requires a new version (breaking change) | Add fields without breaking |
| Documentation | Manual (Swagger, Postman) | Automatic from the SDL schema |
| Caching | Easy HTTP caching | Requires custom caching |
A Simple Implementation Example
I’ll show a simple backend example using Node.js. The following code highlights the difference between REST routes and GraphQL resolvers.
REST API (Express.js):
1const express = require('express');
2const app = express();
3
4const users = [{ id: 1, name: "Budi" }];
5const posts = [{ id: 101, title: "Belajar REST", userId: 1 }];
6
7app.get('/users/:id', (req, res) => {
8 const user = users.find(u => u.id === Number(req.params.id));
9 res.json(user);
10});
11
12app.get('/users/:id/posts', (req, res) => {
13 const userPosts = posts.filter(p => p.userId === Number(req.params.id));
14 res.json(userPosts);
15});
16
17app.listen(3000);GraphQL (Apollo Server):
1const { ApolloServer, gql } = require('apollo-server');
2
3const users = [{ id: 1, name: "Budi" }];
4const posts = [{ id: 101, title: "Belajar REST", userId: 1 }];
5
6const typeDefs = gql`
7 type User {
8 id: Int
9 name: String
10 posts: [Post]
11 }
12 type Post {
13 id: Int
14 title: String
15 }
16 type Query {
17 user(id: Int!): User
18 }
19`;
20
21const resolvers = {
22 Query: {
23 user: (_, args) => users.find(u => u.id === args.id),
24 },
25 User: {
26 posts: (parent) => posts.filter(p => p.userId === parent.id),
27 },
28};
29
30const server = new ApolloServer({ typeDefs, resolvers });
31server.listen({ port: 4000 });When to Use REST? When to Use GraphQL?
GraphQL is a good fit if:
- Your product is frontend-heavy (web/mobile apps) with varied data requirements.
- Over-fetching/under-fetching happens often in your REST API.
- You want the API to evolve quickly without frequent breaking changes.
REST is more suitable if:
- Your API is simple with well-defined resource shapes.
- You want the benefits of simple HTTP caching.
- You have many legacy clients that rely on fixed endpoints.
Conclusion
GraphQL and REST API each have their own strengths and challenges. There’s no single solution for every problem; it depends on the needs of your application, team, and infrastructure.
From personal experience, GraphQL is a huge help in applications that are complex and change frequently. REST, however, remains a safe choice for stable and mature systems. Understand the differences through the two quick comparisons above so you can make the best choice for your next project!
Further Reading:
Happy coding! 🚀