A
AiTechWorlds
AiTechWorlds

| Aspect | REST | GraphQL |
|---|---|---|
| Invented | 2000 (Roy Fielding) | 2015 (Facebook/Meta) |
| Data shape | Server defined per endpoint | Client defined per query |
| Transport | HTTP (GET, POST, PUT, DELETE) | HTTP POST (usually) |
| Type system | None (OpenAPI is optional) | Built in, required |
| Versioning | URL (/v1/, /v2/) | Schema evolution (no versions) |
| Caching | HTTP cache (GET requests) | Manual (POST isn't cached by default) |
GET /users โ list all users
POST /users โ create user
GET /users/42 โ get user 42
PUT /users/42 โ replace user 42
PATCH /users/42 โ partial update user 42
DELETE /users/42 โ delete user 42
GET /users/42/posts โ user's posts (nested resource)GET /users/42
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"role": "admin",
"created_at": "2024-01-15",
"preferences": { ... },
"billing": { ... }
}Over fetching: client receives role, preferences, billing even if it only needed name and email.
Under fetching: to get a user's posts, you need a second request to /users/42/posts.
const express = require('express');
const router = express.Router();
router.get('/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
router.post('/users', async (req, res) => {
const user = await db.users.create(req.body);
res.status(201).json(user);
});| Concept | Description |
|---|---|
| Schema | Typed definition of all data and operations |
| Query | Read data (like GET) |
| Mutation | Write data (like POST/PUT/DELETE) |
| Subscription | Real time updates (WebSocket) |
| Resolver | Function that fetches data for a field |
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
users: [User!]!
posts(authorId: ID): [Post!]!
}
type Mutation {
createUser(name: String!, email: String!): User!
updateUser(id: ID!, name: String): User!
deleteUser(id: ID!): Boolean!
}# Only fetch name and email โ nothing else
query GetUser {
user(id: "42") {
name
email
}
}
# Fetch user AND their posts in one request (no under-fetching)
query UserWithPosts {
user(id: "42") {
name
posts {
title
content
}
}
}mutation CreateUser {
createUser(name: "Bob", email: "bob@example.com") {
id
name
}
}const { ApolloServer, gql } = require('@apollo/server');
const typeDefs = gql`
type User { id: ID!, name: String! }
type Query { user(id: ID!): User }
`;
const resolvers = {
Query: {
user: async (_, { id }) => db.users.findById(id),
},
};
const server = new ApolloServer({ typeDefs, resolvers });| Scenario | REST | GraphQL |
|---|---|---|
| Simple CRUD | Excellent | Overkill |
| Mobile apps (bandwidth sensitive) | Over fetches | Ideal |
| Multiple data sources in one request | Multiple round trips | Single query |
| Public API for third parties | Better documented | Harder to explore |
| Real time (subscriptions) | SSE or WebSocket required | Built in subscriptions |
| File uploads | Native multipart | Requires workaround |
| Browser caching | HTTP cache works natively | Needs Apollo Client cache |
| Type safety | Optional (OpenAPI) | Built in |
| Learning curve | Low | Medium |
Choose REST when:
Choose GraphQL when:
query {
posts { # 1 query
title
author { # N queries (one per post!)
name
}
}
}Fix: DataLoader (batching)
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (ids) => {
const users = await db.users.findByIds(ids);
return ids.map(id => users.find(u => u.id === id));
});
// Now all author fetches batch into one query
const resolvers = {
Post: {
author: (post) => userLoader.load(post.authorId)
}
};/users/42/posts/7/comments/3/likes flatten with query params insteadGet more notes like this daily on Telegram!
Free study notes, cheat sheets & AI tips
Last reviewed on June 13, 2026 by the AiTechWorlds Notes Team. Free cheat sheet no signup required.
Join AiTechWorlds on Telegram and get daily AI tips, prompt engineering templates, coding resources, and exclusive content 100% free!
No spam. Leave anytime.