Skip to main content
CRUD stands for Create, Read, Update, and Delete. These four operations map to HTTP methods and cover the core of any REST API. This page builds a complete CRUD implementation for a users resource using MySQL and the callback pattern with db.query(), organized with MVC.

CRUD to HTTP Mapping

MVC Folder Structure

Database Table

config/db.js

controllers/userController.js

Each export function handles one CRUD operation using db.query() with callbacks.

routes/userRoutes.js

app.js

The Callback Pattern Explained

Every db.query() call follows the same structure:
The return keyword before each res.json() is important. It stops the function from continuing after the response is sent. Without it, Express may try to send multiple responses and crash with “Cannot set headers after they are sent.”

db.query() Results Reference

Postman Testing Steps

1

Create user

POST /api/users with JSON body: name, email, password. Expect 201 + id.
2

Get all users

GET /api/users with Authorization: Bearer token. Expect 200 + array.
3

Get one user

GET /api/users/1. Expect 200 + user object.
4

Update user

PUT /api/users/1 with updated fields. Expect 200.
5

Delete user

DELETE /api/users/1. Expect 204 No Content.
6

Confirm deletion

GET /api/users/1 again. Expect 404 Not Found.

Common Mistakes

Without return, code continues running after sending a response. Node.js throws “Cannot set headers after they are sent to the client.” Always add return before every res.status(...).
db.query() for SELECT always succeeds even if no rows match. Check results.length === 0 to return a 404.
If the ID does not exist, affectedRows is 0 but err is null. Without the affectedRows check you silently return 200.
Deep nesting (callback inside callback inside callback) is hard to read. For complex flows, consider using named functions instead of anonymous inline callbacks to keep nesting shallow.