Dạo này build API mà không có xác thực thì khác gì “nhà không cửa”, dễ bị “hỏi thăm” lắm. Mình đã từng vật lộn với mớ routes lộn xộn, xử lý lỗi rối tung và đặc biệt là khâu bảo mật API. Bài viết này là kinh nghiệm thực chiến của mình, hướng dẫn bạn Express.js tạo REST API hoàn chỉnh từ A-Z với Node.js và MongoDB. Đặc biệt, mình sẽ tập trung vào việc tích hợp xác thực JWT (JSON Web Token) một cách bài bản, an toàn và dễ bảo trì nhất theo chuẩn năm 2026.
Phần quan trọng nhất: Xây dựng nền móng và bộ khung CRUD cho REST API
Xây dựng RESTful API Express.js có xác thực đòi hỏi một nền tảng vững chắc. Bộ khung CRUD chính là trái tim của bất kỳ dịch vụ backend (Backend service) nào, giúp quản lý luồng dữ liệu một cách nhịp nhàng và hiệu quả.
Chuẩn bị “đất và gạch” – Thiết lập môi trường Node.js và khởi tạo dự án Express.js
Để thiết lập dự án Node.js, bạn cần cài đặt môi trường, khởi tạo package.json bằng npm init và cài đặt các package cơ bản như express, mongoose, dotenv.
Cách tạo REST API với Express.js bắt đầu từ những dòng lệnh đơn giản nhất. Đầu tiên, bạn tạo một thư mục trống và mở terminal lên. Chạy lệnh npm init -y để tạo file cấu hình mặc định. Sau đó, chúng ta cài đặt các “vũ khí” cần thiết bằng lệnh: npm install express mongoose dotenv cors jsonwebtoken bcryptjs.
Mỗi package đều có nhiệm vụ riêng. Express lo phần khung server, Mongoose giao tiếp database, Dotenv bảo mật biến môi trường. Để quá trình code nhàn hơn, đừng quên cài Nodemon (phát triển) bằng lệnh npm install -D nodemon. Công cụ này giúp server tự khởi động lại mỗi khi bạn lưu file, tiết kiệm vô số thời gian gõ lệnh thủ công. Đối với những bạn mới chuyển sang làm backend, việc nắm vững nền tảng là rất cần thiết. Bạn có thể tham khảo bài viết Học Node.js từ đầu cho backend developer để củng cố kiến thức trước khi đi sâu hơn.
Nhiều bạn thường hỏi tại Phạm Hải rằng nên chọn ngôn ngữ nào để làm backend khởi nghiệp. Nếu bạn đang phân vân, bài đánh giá PHP vs Node.js so sánh backend 2026 sẽ cho bạn một góc nhìn khách quan nhất về hiệu năng và xu hướng thị trường hiện nay.
Xây dựng “bộ xương” với cấu trúc thư mục dự án REST API Express.js khoa học (Models, Views, Controllers)
Cấu trúc dự án REST API Express.js chuẩn năm 2026 thường áp dụng mô hình MVC, tách biệt rõ ràng giữa Routes, Controllers và Models để dễ dàng mở rộng và bảo trì.
Một dự án gom tất cả code vào file server.js là một thảm họa bảo trì thực sự. Mình khuyên bạn nên chia Cấu trúc thư mục dự án thành các phần riêng biệt ngay từ ngày đầu tiên. Cụ thể, thư mục routes sẽ chứa các Routes (Định tuyến API) làm nhiệm vụ điều hướng. Thư mục controllers chứa logic xử lý (Controller) quyết định API sẽ làm gì. Thư mục models chứa Model (Mô hình dữ liệu) định nghĩa cấu trúc dữ liệu.
- routes/: Nơi định nghĩa các đường dẫn như
/api/users. - controllers/: Nơi chứa các hàm như
createUser,getUser. - models/: Nơi chứa file
User.jsđịnh nghĩa database schema. - middlewares/: Nơi chứa các trạm kiểm soát xác thực.
Cách chia này tuân thủ chặt chẽ REST principles (Nguyên tắc REST), giúp code gọn gàng, ai nhìn vào cũng hiểu. Khi dự án lớn lên, bạn có thể dễ dàng tích hợp thêm TypeScript (trong Express.js) mà không bị ngợp bởi mớ code bùi nhùi. Tất nhiên, để viết logic trơn tru trong các controller, nền tảng ngôn ngữ là cốt lõi. Nếu cảm thấy chưa vững, bạn nên ôn lại qua hướng dẫn Học JavaScript cơ bản cho người mới 2026.
Kết nối với “kho chứa” – Hướng dẫn tạo API Express.js kết nối MongoDB bằng Mongoose
Để kết nối MongoDB, chúng ta sử dụng thư viện Mongoose – một ODM mạnh mẽ giúp định nghĩa Schema và tương tác với cơ sở dữ liệu dễ dàng qua chuỗi kết nối URI.
Hướng dẫn tạo API Express.js kết nối MongoDB không thể thiếu Mongoose. Đây là cầu nối tuyệt vời giúp Node.js nói chuyện với MongoDB một cách trơn tru. Bạn tạo file db.js và sử dụng hàm mongoose.connect() truyền vào chuỗi URI của database.
Việc định nghĩa Schema MongoDB giúp kiểm soát chặt chẽ kiểu dữ liệu đầu vào, tránh việc lưu rác vào database. Ví dụ, schema của User sẽ quy định email là kiểu string, bắt buộc phải có và phải là duy nhất (unique). Quá trình kết nối database hay truy vấn dữ liệu luôn mất một khoảng thời gian chờ đợi phản hồi từ server. Do đó, việc hiểu rõ Async Await Promise JavaScript dễ hiểu là điều kiện bắt buộc để viết code xử lý bất đồng bộ, tránh tình trạng server bị treo cứng chờ database.
Tạo những “viên gạch” đầu tiên – Hướng dẫn CRUD API Node.js Express.js MongoDB (Create, Read, Update, Delete)
Các thao tác CRUD trong Express.js được ánh xạ với các HTTP methods (GET, POST, PUT, DELETE) để tạo, đọc, cập nhật và xóa dữ liệu trên MongoDB một cách chuẩn xác.
Đây là phần cốt lõi và thú vị nhất trong bài Hướng dẫn CRUD API Node.js Express.js MongoDB này. Express.js tạo API từng bước cực kỳ logic. Mỗi thao tác sẽ tương ứng với một Endpoint API cụ thể. Dưới đây là bảng tóm tắt cách map các phương thức:
| Thao tác (CRUD) | HTTP Methods | Nhiệm vụ chính |
|---|---|---|
| Create | POST | Tạo mới một bản ghi (ví dụ: tạo user mới) |
| Read | GET | Lấy danh sách hoặc chi tiết một bản ghi |
| Update / Delete | PUT / DELETE | Cập nhật toàn bộ hoặc xóa bản ghi theo ID |
Khi xây dựng các endpoint này, hãy luôn nhớ trả về mã trạng thái HTTP chuẩn (như 200 OK cho thành công, 201 Created khi tạo mới, 404 Not Found khi không có dữ liệu). Tư duy thiết kế API này áp dụng chung cho mọi ngôn ngữ lập trình. Nếu bạn tò mò cách các framework khác xử lý kiến trúc này, bạn có thể xem thêm cách Xây dựng REST API bằng PHP Laravel để thấy sự tương đồng thú vị giữa các công nghệ backend.
Tăng cường an ninh: Tích hợp “khóa cửa” JWT cho API
Bảo mật API Express.js là yếu tố sống còn không thể xem nhẹ. Tích hợp JWT (JSON Web Token) và Xác thực (Authentication) đúng cách giúp bảo vệ dữ liệu người dùng khỏi các cuộc tấn công mạng nguy hiểm.
JWT là gì? Tại sao lại là lựa chọn tối ưu để bảo mật API Express.js?
JWT (JSON Web Token) là tiêu chuẩn xác thực phi trạng thái (stateless), giúp server không cần lưu trữ session, từ đó tăng cường khả năng mở rộng và bảo mật cho API.
Với các thiết kế Stateless API (API phi trạng thái), server không cần nhớ ai đang đăng nhập. Mọi thông tin chứng thực đều nằm gọn trong một đoạn chuỗi token mã hóa. Điều này mang lại Khả năng mở rộng (Scalability) tuyệt vời vì bạn có thể chạy hàng chục server đằng sau Load Balancer mà không lo mất session. Quản lý phiên (Session management) truyền thống đôi khi khá cồng kềnh và tốn RAM, trong khi JWT lại nhẹ nhàng và cực kỳ linh hoạt cho các ứng dụng mobile hay Single Page Application.
Cấu trúc của một JWT bao gồm Header, Payload (chứa data user) và Signature (chữ ký bảo mật). Tuy nhiên, token JWT rất dễ bị kẻ gian đánh cắp nếu đường truyền mạng bị nghe lén. Do đó, việc mã hóa đường truyền bằng chứng chỉ bảo mật là bắt buộc. Bạn có thể tìm hiểu SSL HTTPS là gì cách cài cho website để đảm bảo token của người dùng luôn được mã hóa an toàn trên môi trường production.
Tạo API đăng ký đăng nhập với Express.js JWT – Mã hóa mật khẩu an toàn với Bcryptjs
Khi tạo API đăng ký và đăng nhập, mật khẩu người dùng bắt buộc phải được băm (hash) bằng thư viện Bcryptjs trước khi lưu vào database để chống rò rỉ dữ liệu.
Tạo API đăng ký đăng nhập với Express.js JWT bắt đầu bằng việc nhận thông tin từ người dùng qua req.body. Nguyên tắc bất di bất dịch: Tuyệt đối không bao giờ lưu mật khẩu dạng plain-text (chữ thường) vào database. Tại Phạm Hải, chúng mình luôn khuyên các dự án dùng Bcryptjs (băm mật khẩu) với cấu hình saltRounds từ 10 đến 12 để cân bằng giữa bảo mật và hiệu năng.
Khi người dùng đăng nhập đúng tài khoản và mật khẩu, server sẽ dùng hàm jwt.sign() để tạo ra một token. Theo các cập nhật bảo mật mới nhất năm 2026, access token chỉ nên có tuổi thọ ngắn (khoảng 15 phút) để hạn chế rủi ro nếu token bị lộ. Bạn có thể kết hợp thêm Passport.js (xác thực) nếu hệ thống của bạn yêu cầu tính năng đăng nhập nhanh qua Google, Apple hoặc Facebook.
Phân quyền cho API – Cách tạo Middleware để kiểm tra token và phân quyền truy cập
Middleware trong Express.js đóng vai trò như trạm kiểm soát, giúp xác thực token JWT hợp lệ và thực hiện Phân quyền (Authorization) truy cập cho từng endpoint cụ thể.
Middleware bản chất là một hàm đứng giữa request của người dùng và response của server. Khi một request gửi đến các route cần bảo vệ (như xem profile, đổi mật khẩu), middleware sẽ chặn lại để kiểm tra. Nó sẽ trích xuất token từ header Authorization, sau đó dùng hàm jwt.verify() cùng với Secret Key để giải mã.
Nếu token hợp lệ và chưa hết hạn, middleware sẽ gán thông tin user (như userId) vào object req.user và gọi hàm next() để cho phép request đi tiếp vào Controller. Đây chính là cốt lõi của hệ thống Phân quyền (Authorization). Bạn hoàn toàn có thể viết thêm logic để kiểm tra role (ví dụ: chỉ admin mới được xóa bài viết) ngay bên trong middleware này.
Dùng Postman để “thử khóa” – Kiểm tra các Endpoint API yêu cầu xác thực
Postman là công cụ không thể thiếu giúp gửi các HTTP request kèm theo Authorization header chứa token JWT để kiểm thử các endpoint bảo mật.
Sau khi code xong phần xác thực, bạn không thể dùng trình duyệt thông thường để test các route POST, PUT hay các route yêu cầu token. Postman (kiểm thử API) sinh ra để giải quyết bài toán này. Bạn chỉ cần copy đoạn token nhận được từ API login thành công, dán vào mục Authorization (chọn loại Bearer Token) và nhấn nút Send để gửi request.
Việc test kỹ lưỡng các luồng dữ liệu trên Postman giúp đảm bảo API hoạt động đúng 100% trước khi bàn giao cho đội frontend. Sau khi API đã chạy ngon lành và bảo mật, lập trình viên frontend sẽ dùng mã JavaScript để gọi nó. Bạn có thể xem chi tiết cách Fetch API gọi REST API bằng JavaScript để hiểu rõ luồng giao tiếp thực tế giữa client và server.
Nâng cao tay nghề: Những “bí kíp” thực hành tốt nhất khi tạo REST API với Express.js

Thực hành tốt nhất khi tạo REST API với Express.js bao gồm chuẩn hóa mã lỗi, bảo mật dữ liệu và tối ưu cấu hình trước khi tiến hành Triển khai API (Deployment) lên server thực tế.
Xử lý lỗi (Error Handling) chuyên nghiệp: Đừng để người dùng thấy những lỗi “trời ơi đất hỡi”
Xử lý lỗi tập trung bằng một middleware duy nhất giúp API trả về các mã trạng thái HTTP chuẩn xác và ẩn đi các chi tiết lỗi nhạy cảm của server.
Xử lý lỗi (Error handling) lộn xộn, mỗi nơi trả về một kiểu JSON khác nhau là căn bệnh cực kỳ phổ biến của người mới làm API. Thay vì rải rác console.log khắp nơi, hãy tạo một middleware xử lý lỗi global (thường có 4 tham số err, req, res, next) nằm ở cuối cùng của file app.js. Bất cứ khi nào có lỗi trong hệ thống, bạn chỉ cần gọi next(error).
Middleware này sẽ format lỗi thành một chuỗi JSON thống nhất (bao gồm status, message) và trả về cho client, đồng thời giấu đi stack trace (chi tiết lỗi code) khi chạy ở chế độ production. Để hiểu sâu hơn về tư duy bắt lỗi an toàn trong code, việc áp dụng Xử lý lỗi JavaScript try catch best practices trong từng hàm controller là một bước đi khôn ngoan không thể bỏ qua.
Kiểm tra dữ liệu đầu vào (Input Validation) – Nguyên tắc “không bao giờ tin tưởng người dùng”
Sử dụng các thư viện như Joi hoặc Zod để Kiểm tra dữ liệu đầu vào (Input validation) từ body, params, query trước khi đưa vào xử lý logic database.
“Đừng bao giờ tin những gì client gửi lên” là câu thần chú của mọi backend developer. Nếu bạn mong đợi một số nguyên tuổi tác, hãy chắc chắn nó là số nguyên. Nếu bạn cần email, hãy kiểm tra chặt chẽ định dạng email đó. Việc validate này giúp chặn đứng các lỗi vặt làm crash server và hạn chế tối đa nguy cơ bị NoSQL Injection. Hiện nay năm 2026, Zod đang là thư viện được cộng đồng Node.js cực kỳ ưa chuộng nhờ cú pháp khai báo gọn gàng và khả năng suy luận kiểu dữ liệu cực tốt.
Quản lý biến môi trường với file .env – Tách biệt cấu hình và code
File .env giúp lưu trữ an toàn các thông tin nhạy cảm như chuỗi kết nối database, JWT secret key, tách biệt hoàn toàn Biến môi trường (.env) khỏi mã nguồn chia sẻ.
Bất cứ thứ gì được xem là “bí mật” (mật khẩu database, API keys của bên thứ ba, secret key của JWT) tuyệt đối không bao giờ được hardcode trực tiếp vào file .js. Hãy đưa tất cả chúng vào một file .env ở thư mục gốc và dùng package dotenv để đọc cấu hình vào process.env. Một lưu ý sống còn: Đừng quên thêm file .env vào danh sách .gitignore ngay lập tức để tránh thảm họa vô tình đẩy toàn bộ bí mật công ty lên kho lưu trữ GitHub công khai nhé.
Vượt qua rào cản CORS (Cross-Origin Resource Sharing) khi phát triển
Cấu hình middleware CORS đúng cách giúp frontend ở các domain khác nhau có thể gọi API một cách an toàn mà không bị trình duyệt chặn CORS (chia sẻ tài nguyên chéo nguồn gốc).
Khi frontend React của bạn chạy ở http://localhost:3000 còn backend Node.js lại chạy ở http://localhost:5000, trình duyệt web sẽ tự động chặn các request gọi qua lại vì chúng khác nguồn gốc. Cài đặt và sử dụng package cors trong Express.js sẽ giải quyết triệt để vấn đề đau đầu này. Tuy nhiên, khi đưa dự án lên production, hãy cấu hình tham số origin của CORS chỉ cho phép các domain frontend hợp lệ được phép truy cập để đảm bảo an toàn tối đa cho hệ thống.
Vậy là bạn đã có trong tay bản thiết kế chi tiết để Express.js tạo REST API hoàn chỉnh, bảo mật và có cấu trúc tốt nhất hiện nay. Đừng chỉ đọc lý thuyết xuông, hãy mở ngay VS Code lên và bắt tay vào gõ từng dòng code. Quá trình tự tay xây dựng, gặp lỗi đỏ lòm trên terminal rồi tìm cách sửa lỗi chính là con đường ngắn nhất để bạn làm chủ công nghệ backend. Nhớ rằng, một API xuất sắc không chỉ là API chạy đúng kết quả, mà còn phải là một hệ thống dễ dàng cho người khác đọc hiểu, bảo trì và mở rộng trong tương lai.
Nếu có bất kỳ thắc mắc nào trong quá trình thực hành cấu hình Express.js hay MongoDB, đừng ngần ngại để lại bình luận bên dưới, mình sẽ cố gắng giải đáp nhanh nhất có thể!
Lưu ý: Thông tin trong bài viết này chỉ mang tính chất tham khảo. Để có lời khuyên tốt nhất, vui lòng liên hệ trực tiếp với chúng tôi để được tư vấn cụ thể dựa trên nhu cầu thực tế của bạn.