Express.js là gì? Hướng dẫn xây dựng Backend với Node.js (2026)
Nhiều người học JavaScript thường bắt đầu với phía frontend — tức là những gì hiển thị trên trình duyệt. Nhưng khi muốn tiến xa hơn, bạn sẽ cần biết về backend: phần xử lý dữ liệu, kết nối database, xác thực người dùng và cung cấp API.
Đây chính là lúc Express.js tỏa sáng. Nếu bạn đã biết JavaScript, bạn có thể dùng ngôn ngữ quen thuộc đó để viết code phía server. Đây là điểm mạnh lớn nhất của sự kết hợp Express.js + Node.js.
Bài viết này sẽ hướng dẫn bạn từ khái niệm cơ bản đến xây dựng REST API hoàn chỉnh với Express.js.
Express.js là gì?
Định nghĩa
Express.js là một web framework tối giản và linh hoạt dành cho Node.js. Express được tạo bởi TJ Holowaychuk năm 2010 và hiện được duy trì bởi OpenJS Foundation.
"Framework" nghe có vẻ phức tạp, nhưng đơn giản mà nói: Express là một hộp công cụ tập hợp sẵn những tính năng hay dùng nhất khi xây dựng web server, giúp bạn không phải tự viết lại từ đầu.
Tại sao cần framework? Node.js thuần không đủ sao?
Bạn có thể dùng Node.js thuần để tạo web server, nhưng code sẽ rất phức tạp:
// Cách làm với Node.js thuần — rất phức tạp
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/api/articles' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ articles: [] }));
} else if (req.url === '/api/articles' && req.method === 'POST') {
// Phải tự parse JSON thủ công
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
const data = JSON.parse(body);
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
});
}
});
server.listen(3000);
So sánh với Express.js:
// Cách làm với Express.js — đơn giản hơn rất nhiều
const express = require('express');
const app = express();
app.use(express.json()); // Tự động parse JSON
app.get('/api/articles', (req, res) => {
res.json({ articles: [] });
});
app.post('/api/articles', (req, res) => {
res.status(201).json(req.body); // req.body đã có dữ liệu sẵn
});
app.listen(3000);
Express xử lý những phần nhàm chán giúp bạn, để bạn tập trung vào logic thực sự của ứng dụng.
Tại sao Express.js phổ biến đến vậy?
- Hơn 53 triệu lượt tải npm mỗi tuần (2026)
- Dễ học — nếu biết JavaScript, bạn có thể bắt đầu trong vài giờ
- "Unopinionated" — không ép buộc cách tổ chức code, bạn tự quyết định
- Hệ sinh thái middleware phong phú
- Được sử dụng bởi Uber, IBM, PayPal và hàng nghìn công ty
- Cộng đồng lớn, tài liệu phong phú
Express 5.x — Phiên bản hiện tại (2026)
Phiên bản ổn định hiện tại là Express 5.x. So với Express 4.x, phiên bản mới hỗ trợ async/await tốt hơn, cải thiện hiệu năng và bảo mật.
Cài đặt Express.js
Yêu cầu trước khi bắt đầu
Bạn cần có Node.js đã được cài đặt. Kiểm tra bằng lệnh:
node --version # v20.x.x trở lên được khuyến nghị
npm --version # 10.x.x trở lên
Nếu chưa có Node.js, hãy xem hướng dẫn cài đặt Node.js trước.
Khởi tạo project
# Tạo thư mục mới cho project
mkdir my-express-app
cd my-express-app
# Khởi tạo package.json (dùng -y để chọn tất cả giá trị mặc định)
npm init -y
Lệnh này tạo ra file package.json — file quản lý thông tin và dependencies của project. Tìm hiểu thêm về npm nếu bạn chưa quen.
Cài đặt Express
npm install express
Sau lệnh này, thư mục node_modules/ và file package-lock.json sẽ được tạo ra.
Server đầu tiên của bạn
Tạo file app.js:
// app.js
const express = require('express'); // Nạp module Express
const app = express(); // Tạo ứng dụng Express
const PORT = 3000; // Định nghĩa cổng (port)
// Xử lý GET request đến URL "/"
app.get('/', (req, res) => {
res.send('Xin chào! Đây là server Express.js đầu tiên của bạn.');
});
// Khởi động server
app.listen(PORT, () => {
console.log(`Server đang chạy tại http://localhost:${PORT}`);
});
Chạy server:
node app.js
# Server đang chạy tại http://localhost:3000
Mở trình duyệt và truy cập http://localhost:3000 — bạn sẽ thấy thông báo "Xin chào!".
Routing cơ bản trong Express.js
Routing là gì?
Routing là cách bạn định nghĩa: "Khi có request đến URL này với method này, thì chạy đoạn code đó."
Ví dụ:
- GET
/api/articles→ Trả về danh sách bài viết - GET
/api/articles/1→ Trả về bài viết có ID=1 - POST
/api/articles→ Tạo bài viết mới
4 HTTP method chính
// app.js
const express = require('express');
const app = express();
app.use(express.json()); // Middleware parse JSON body
// GET — Lấy dữ liệu
app.get('/api/users', (req, res) => {
res.json({ message: 'Danh sách người dùng' });
});
// POST — Tạo dữ liệu mới
app.post('/api/users', (req, res) => {
const { name, email } = req.body; // Lấy dữ liệu từ request body
res.status(201).json({
message: 'Tạo người dùng thành công',
user: { name, email }
});
});
// PUT — Cập nhật dữ liệu (toàn bộ)
app.put('/api/users/:id', (req, res) => {
const userId = req.params.id; // Lấy tham số từ URL
res.json({ message: `Cập nhật người dùng ${userId}` });
});
// DELETE — Xóa dữ liệu
app.delete('/api/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ message: `Đã xóa người dùng ${userId}` });
});
app.listen(3000, () => console.log('Server đang chạy tại port 3000'));
URL Parameters (req.params)
// /api/articles/42 → req.params.id = "42"
app.get('/api/articles/:id', (req, res) => {
const id = req.params.id;
res.json({ message: `Bài viết ID: ${id}` });
});
Query String (req.query)
// /api/articles?page=2&limit=10
app.get('/api/articles', (req, res) => {
const page = req.query.page || 1; // Mặc định là trang 1
const limit = req.query.limit || 10; // Mặc định 10 bài/trang
res.json({
message: `Trang ${page}, hiển thị ${limit} bài`
});
});
Middleware trong Express là gì?
Middleware là khái niệm cốt lõi của Express, và cũng là điểm khiến nhiều người mới bị nhầm lẫn. Hãy cùng hiểu rõ.
Middleware là gì?
Middleware là các hàm trung gian được thực thi giữa lúc nhận request và lúc gửi response. Bạn có thể hình dung như một dây chuyền sản xuất:
Request đến → [Middleware 1] → [Middleware 2] → [Route Handler] → Response gửi đi
Mỗi middleware nhận 3 tham số: req, res, và next.
Lưu ý quan trọng: Nếu middleware không gọi next(), request sẽ bị "treo" ở đó, không đi tiếp được.
Built-in Middleware (có sẵn trong Express)
const express = require('express');
const app = express();
// Parse JSON request body (dùng với API nhận dữ liệu JSON)
app.use(express.json());
// Parse dữ liệu từ HTML form
app.use(express.urlencoded({ extended: true }));
// Phục vụ file tĩnh (HTML, CSS, ảnh) từ thư mục "public"
app.use(express.static('public'));
Third-party Middleware (cài thêm)
npm install cors morgan helmet
const cors = require('cors'); // Cho phép request từ domain khác
const morgan = require('morgan'); // Ghi log request HTTP
const helmet = require('helmet'); // Tăng cường bảo mật HTTP headers
app.use(cors()); // Cho phép mọi origin gọi API
app.use(morgan('dev')); // Log: GET /api/articles 200 5.123 ms
app.use(helmet()); // Tự động thêm security headers
Custom Middleware
// Middleware ghi log thời gian của mỗi request
const customLogger = (req, res, next) => {
const time = new Date().toISOString();
console.log(`[${time}] ${req.method} ${req.url}`);
next(); // BẮT BUỘC phải gọi next() để đi tiếp!
};
// Middleware kiểm tra xác thực
const authCheck = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
// Không có token → trả về lỗi 401, không gọi next()
return res.status(401).json({ message: 'Cần đăng nhập' });
}
next(); // Có token → cho đi tiếp
};
// Áp dụng cho toàn bộ app
app.use(customLogger);
// Áp dụng chỉ cho route cụ thể
app.get('/api/profile', authCheck, (req, res) => {
res.json({ message: 'Thông tin cá nhân' });
});
Error Handling Middleware
// Middleware xử lý lỗi — có 4 tham số, phải đặt cuối cùng
app.use((err, req, res, next) => {
console.error('Lỗi xảy ra:', err.message);
res.status(err.status || 500).json({
message: 'Có lỗi xảy ra!',
// Chỉ hiện chi tiết lỗi ở môi trường development
error: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});
Xây dựng REST API với Express.js
REST API là cách phổ biến nhất để frontend và backend giao tiếp với nhau. Dữ liệu được truyền dưới dạng JSON.
Dưới đây là code CRUD hoàn chỉnh cho API quản lý bài viết — bạn có thể copy và chạy ngay:
// app.js - REST API quản lý bài viết
const express = require('express');
const app = express();
const PORT = 3000;
// Middleware parse JSON body
app.use(express.json());
// Dữ liệu tạm thời trong bộ nhớ (thực tế dùng database)
const articles = [
{ id: 1, title: 'JavaScript là gì?', author: 'Admin', createdAt: '2026-01-01' },
{ id: 2, title: 'Node.js tutorial', author: 'Admin', createdAt: '2026-01-02' }
];
let nextId = 3; // ID tiếp theo (thực tế do database tự tạo)
// GET /api/articles — Lấy tất cả bài viết
app.get('/api/articles', (req, res) => {
res.json({
success: true,
data: articles,
total: articles.length
});
});
// GET /api/articles/:id — Lấy 1 bài viết theo ID
app.get('/api/articles/:id', (req, res) => {
const id = parseInt(req.params.id);
const article = articles.find(a => a.id === id);
if (!article) {
return res.status(404).json({
success: false,
message: 'Không tìm thấy bài viết'
});
}
res.json({ success: true, data: article });
});
// POST /api/articles — Tạo bài viết mới
app.post('/api/articles', (req, res) => {
const { title, author } = req.body;
// Kiểm tra dữ liệu đầu vào
if (!title || !author) {
return res.status(400).json({
success: false,
message: 'Thiếu trường title hoặc author'
});
}
const newArticle = {
id: nextId++,
title,
author,
createdAt: new Date().toISOString().split('T')[0]
};
articles.push(newArticle);
res.status(201).json({ success: true, data: newArticle });
});
// PUT /api/articles/:id — Cập nhật bài viết
app.put('/api/articles/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = articles.findIndex(a => a.id === id);
if (index === -1) {
return res.status(404).json({
success: false,
message: 'Không tìm thấy bài viết'
});
}
// Dùng spread operator để giữ lại dữ liệu cũ, ghi đè dữ liệu mới
articles[index] = { ...articles[index], ...req.body };
res.json({ success: true, data: articles[index] });
});
// DELETE /api/articles/:id — Xóa bài viết
app.delete('/api/articles/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = articles.findIndex(a => a.id === id);
if (index === -1) {
return res.status(404).json({
success: false,
message: 'Không tìm thấy bài viết'
});
}
articles.splice(index, 1);
res.json({
success: true,
message: 'Đã xóa bài viết thành công'
});
});
// Khởi động server
app.listen(PORT, () => {
console.log(`Server đang chạy tại http://localhost:${PORT}`);
});
Express.js vs NestJS vs Fastify — So sánh chi tiết
Khi học backend với Node.js, bạn sẽ gặp nhiều lựa chọn framework. Bảng dưới giúp bạn hiểu sự khác nhau:
| Tiêu chí | Express.js | Fastify | NestJS |
|---|---|---|---|
| Độ phổ biến | Cao nhất | Cao | Cao |
| Hiệu năng | Trung bình | Nhanh hơn Express ~2x | Tương đương Express |
| Độ khó học | Dễ | Dễ - Trung bình | Khó (learning curve cao) |
| Cấu trúc code | Tự do | Nhẹ, linh hoạt | Cố định (MVC + DI) |
| TypeScript | Cần cấu hình thêm | Hỗ trợ tốt | TypeScript mặc định |
| Phù hợp với | Học backend, API vừa-nhỏ | API hiệu năng cao | Dự án lớn, enterprise |
Kết luận: Nếu bạn đang bắt đầu học backend, hãy chọn Express.js. Sau khi thành thạo Express, việc chuyển sang Fastify hay NestJS sẽ dễ dàng hơn nhiều.
Cấu trúc thư mục Express project
Khi project nhỏ, để tất cả vào app.js là ổn. Nhưng khi code tăng lên, bạn cần tổ chức theo MVC pattern (Model-View-Controller).
Cấu trúc thư mục đề xuất
my-express-app/
├── app.js # Entry point — khởi động server
├── package.json
├── .env # Biến môi trường (mật khẩu DB...)
├── .gitignore # Loại trừ node_modules, .env
│
├── routes/ # Định nghĩa routes
│ ├── index.js # Tập hợp tất cả routes
│ ├── articles.js # Routes cho /api/articles
│ └── users.js # Routes cho /api/users
│
├── controllers/ # Logic xử lý
│ ├── articleController.js
│ └── userController.js
│
├── models/ # Data models
│ ├── Article.js
│ └── User.js
│
├── middleware/ # Custom middleware
│ ├── auth.js # Xác thực
│ └── logger.js # Ghi log
│
└── config/ # Cấu hình
└── database.js # Kết nối database
Express Router — Tách routes ra file riêng
// routes/articles.js
const express = require('express');
const router = express.Router(); // Tạo router riêng
// Các route trong file này sẽ được gắn vào /api/articles
router.get('/', (req, res) => {
res.json({ message: 'Danh sách tất cả bài viết' });
});
router.get('/:id', (req, res) => {
res.json({ message: `Bài viết ID: ${req.params.id}` });
});
router.post('/', (req, res) => {
res.status(201).json({ message: 'Tạo bài viết mới', data: req.body });
});
module.exports = router; // Export router để dùng ở app.js
// app.js — File chính
const express = require('express');
const app = express();
// Import các router
const articlesRouter = require('./routes/articles');
const usersRouter = require('./routes/users');
app.use(express.json());
// Gắn router vào đường dẫn tương ứng
app.use('/api/articles', articlesRouter); // /api/articles/... → articlesRouter
app.use('/api/users', usersRouter); // /api/users/... → usersRouter
app.listen(3000, () => console.log('Server đang chạy'));
Câu hỏi thường gặp về Express.js
Express.js có cần biết Node.js trước không?
Có. Bạn nên hiểu cơ bản về require()/module.exports, async/await, và cách dùng npm trước khi học Express. Nếu chưa có nền tảng Node.js, hãy bắt đầu từ đây.
Express.js và Node.js khác nhau thế nào?
Node.js là môi trường thực thi (runtime) — cho phép chạy JavaScript ngoài trình duyệt. Express.js là framework xây dựng trên Node.js, cung cấp thêm các tính năng tiện ích cho web server. Nói hình tượng: Node.js là nền đất, Express.js là ngôi nhà xây trên đó.
Học Express.js mất bao lâu?
Nếu đã biết JavaScript và Node.js cơ bản, bạn có thể nắm vững Express.js trong 1-2 tuần. Để tự xây dựng được một REST API hoàn chỉnh cần khoảng 1 tháng luyện tập.
Express.js có thể làm được những gì?
- Xây dựng REST API / GraphQL API
- Web app có server-side rendering (dùng EJS, Pug)
- Backend cho ứng dụng di động
- Microservices
- Realtime app (kết hợp với Socket.io)
Nên dùng Express 4 hay Express 5?
Hãy dùng Express 5.x — đây là phiên bản ổn định hiện tại (2026). Express 5 hỗ trợ async/await tốt hơn, lỗi trong async function được tự động chuyển đến error handler mà không cần try/catch thủ công.
Express.js có dùng được với TypeScript không?
Có. Cài thêm @types/express là dùng được ngay. Tuy nhiên nếu TypeScript là ưu tiên hàng đầu, NestJS hoặc Fastify là lựa chọn tốt hơn vì chúng hỗ trợ TypeScript tốt hơn theo mặc định.
Kết luận
Express.js là điểm vào hoàn hảo để bắt đầu hành trình phát triển backend với JavaScript. Framework này đủ đơn giản để học nhanh, nhưng đủ mạnh để xây dựng ứng dụng thực tế.
Tóm lại những gì bạn đã học trong bài này:
- Express.js là gì — Framework web tối giản cho Node.js, giúp xây dựng server dễ hơn nhiều
- Cài đặt — Chỉ cần
npm install express - Routing — Định nghĩa cách xử lý từng URL với GET/POST/PUT/DELETE
- Middleware — Lớp xử lý trung gian, chạy trước route handler
- REST API — Xây dựng CRUD API hoàn chỉnh chỉ với ~60 dòng code
- Cấu trúc project — Tổ chức code theo MVC với Express Router
Bước tiếp theo: Sau khi thành thạo Express.js, hãy kết nối với database (MongoDB hoặc PostgreSQL) để dữ liệu được lưu trữ thực sự. Tham khảo thêm lộ trình học backend 2026 để biết toàn bộ hành trình phía trước.
Cách học hiệu quả nhất: Hãy copy đoạn code CRUD ở trên, chạy thử, sau đó tự viết lại từ đầu mà không nhìn. Đó là cách duy nhất để thực sự hiểu Express.js.