Hey everyone ๐
I first started learning GraphQL back in 2020, and since then, Iโve used it in two real projects during my career as a Software Engineer. At first, it looked too different from the REST style I was used to, but it didnโt take long to see its strengths, especially when dealing with flexible UIs.
If you're already familiar with REST and wondering how it maps to GraphQL in a CRUD scenario, this post is for you.
Letโs migrate a basic User API (Create, Read, Update, Delete) from REST to GraphQL, and see what changes.
๐ท The REST Setup
Hereโs a classic REST API with Node.js + Express:
// GET /users
app.get('/users', async (req, res) => {
const users = await db.users.find();
res.json(users);
});
// GET /users/:id
app.get('/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user);
});
// POST /users
app.post('/users', async (req, res) => {
const newUser = await db.users.insert(req.body);
res.status(201).json(newUser);
});
// PUT /users/:id
app.put('/users/:id', async (req, res) => {
const updated = await db.users.update(req.params.id, req.body);
res.json(updated);
});
// DELETE /users/:id
app.delete('/users/:id', async (req, res) => {
await db.users.delete(req.params.id);
res.status(204).send();
});
It works well, but you usually need to version your routes (/api/v1/...), validate everything manually, and deal with over/underfetching on the frontend.
โก The GraphQL Version
Instead of many endpoints, GraphQL has one โ and you control everything through queries and mutations.
๐ธ Schema Definition
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
type User {
id: ID!
name: String!
email: String!
}
input CreateUserInput {
name: String!
email: String!
}
input UpdateUserInput {
name: String
email: String
}
๐ Queries (Read)
All users:
query {
users {
id
name
email
}
}
Single user by ID:
query {
user(id: 1) {
name
email
}
}
โ๏ธ Mutations (Write)
Create a user:
mutation {
createUser(input: { name: "Felipe", email: "felipe@example.com" }) {
id
name
}
}
Update a user:
mutation {
updateUser(id: 1, input: { name: "Felipe Updated" }) {
id
name
}
}
Delete a user:
mutation {
deleteUser(id: 1)
}
๐ ๏ธ Example Resolver Setup (Apollo Server)
const resolvers = {
Query: {
users: (_, __, { db }) => db.users.find(),
user: (_, { id }, { db }) => db.users.findById(id),
},
Mutation: {
createUser: (_, { input }, { db }) => db.users.insert(input),
updateUser: (_, { id, input }, { db }) => db.users.update(id, input),
deleteUser: async (_, { id }, { db }) => {
await db.users.delete(id);
return true;
},
},
};
โ
Why Migrate?
Hereโs what I liked after migrating REST endpoints to GraphQL:
One single endpoint for everything
Flexible queries on the frontend โ no under/overfetch
Strong typing from the schema
Easier to evolve without versioning routes
Of course, GraphQL adds some learning curve and server-side complexity. But in return, the client experience gets much cleaner, especially for frontend-heavy applications.
Top comments (0)