This Example will show you how to make a REST API using Express.js and MySQL.
The database of the example contains two tables: book and user. The user-table will be used to authorize the REST API users. So, in the exercise you will build a login system, so that the credentials will be checked based on the user.
The example follows the MVC (Model–View–Controller) pattern.
In a typical MVC Express application, you would have three separate folders:
models/ → handles database queries and data logic
controllers/ → contains the business logic that runs when a route is accessed
routes/ → maps URL paths to controller functions
In the application built in these examples, we use a simplified two-folder structure with only routes/ and models/. The route files take on the role of controllers as well — they both define the URL paths and contain the request-handling logic directly. This approach keeps the project easier to follow when learning, without splitting logic across multiple files.
To see how the book controller example would look when separated into routes and controllers folders, click the button below:
×
Separating Routes and Controllers
Here's how the book.js example can be split into separate routes and controllers files
following the MVC pattern. This structure is recommended for larger applications.
Benefits of Separation:
Better code organization and maintainability
Easier testing of business logic
Clearer separation of concerns (routing vs logic)
Reusable controller functions
📄 routes/book.js
const express = require('express');
const router = express.Router();
const bookController = require('../controllers/bookController');
// GET all books
router.get('/', bookController.getAllBooks);
// GET one book by id
router.get('/:id', bookController.getOneBook);
// POST new book
router.post('/', bookController.addBook);
// DELETE book by id
router.delete('/:id', bookController.deleteBook);
// PUT (update) book by id
router.put('/:id', bookController.updateBook);
module.exports = router;
Purpose: Defines routes and maps them to controller functions
📄 controllers/bookController.js
const book = require('../models/book_model');
// Get all books
exports.getAllBooks = function(request, response) {
book.getAll(function(err, dbResult) {
if (err) {
response.json(err);
} else {
console.log(dbResult);
response.json(dbResult);
}
});
};
// Get one book by id
exports.getOneBook = function(request, response) {
book.getOne(request.params.id, function(err, dbResult) {
if (err) {
response.json(err);
} else {
response.json(dbResult);
}
});
};
// Add new book
exports.addBook = function(request, response) {
book.add(request.body, function(err, dbResult) {
if (err) {
response.json(err);
} else {
response.json(dbResult);
}
});
};
// Delete book by id
exports.deleteBook = function(request, response) {
book.delete(request.params.id, function(err, dbResult) {
if (err) {
response.json(err);
} else {
response.json(dbResult);
}
});
};
// Update book by id
exports.updateBook = function(request, response) {
book.update(request.params.id, request.body, function(err, dbResult) {
if (err) {
response.json(err);
} else {
response.json(dbResult);
}
});
};
Purpose: Contains the business logic for handling requests