Khám phá công nghệ

Khám phá các công cụ và kỹ thuật hữu ich cho Lập trình viên

[MERN Stack] - Bài 1: Node.js Express và MongoDB: Xây dựng ví dụ về CRUD Rest API (Backend)

Thắng Nguyễn

Mon, 29 Apr 2024

[MERN Stack] - Bài 1: Node.js Express và MongoDB: Xây dựng ví dụ về CRUD Rest API (Backend) nodejs_mongo.md

Node.js Express và MongoDB: Xây dựng ví dụ về CRUD Rest API

Express là một trong những framework web phổ biến nhất cho Node.js, hỗ trợ routing, middleware, view system… Mongoose là một ODM (Object Data Modeling) dựa trên Promise cho MongoDB trong Node.js, cung cấp một giải pháp dựa trên schema để mô hình dữ liệu ứng dụng cùng với việc tạo kiểu tự động, validation, xây dựng truy vấn, hooks… Trong bài hướng dẫn này, sẽ hướng dẫn bạn từng bước để xây dựng Node.js Restful API cho các hoạt động CRUD bằng cách sử dụng Express, Mongoose với cơ sở dữ liệu MongoDB.

1. Giới thiệu tổng quan về hướng dẫn

Chúng ta sẽ xây dựng các Rest API có thể tạo mới, lấy, cập nhật, xóa và tìm kiếm các Tutorials. Đầu tiên, chúng ta bắt đầu với một máy chủ web Express. Tiếp theo, chúng ta thêm cấu hình cho cơ sở dữ liệu MongoDB, tạo mô hình Tutorial với Mongoose, viết controller. Sau đó, chúng ta xác định các route để xử lý tất cả các hoạt động CRUD (bao gồm cả tìm kiếm tùy chỉnh).

Mục dưới đây cho thấy tổng quan về các Rest API sẽ được xây dựng:

  • GET api/tutorials Lấy tất cả các Tutorials
  • GET api/tutorials/:id Lấy Tutorial theo id
  • POST api/tutorials Thêm mới Tutorial
  • PUT api/tutorials/:id Cập nhật Tutorial theo id
  • DELETE api/tutorials/:id Xóa Tutorial theo id
  • DELETE api/tutorials Xóa tất cả các Tutorials
  • GET api/tutorials/published Tìm tất cả các Tutorials đã xuất bản
  • GET api/tutorials?title=[kw] Tìm tất cả các Tutorials có tiêu đề chứa kw

Cuối cùng, chúng ta sẽ kiểm tra Rest APIs bằng cách sử dụng Postman.

2. Tạo Ứng dụng Node.js

Đầu tiên, chúng ta tạo một thư mục:

$ mkdir nodejs-mongodb $ cd nodejs-mongodb

Tiếp theo, chúng ta khởi tạo Ứng dụng Node.js với một tệp package.json:

npm init

Sau đó cài đặt các module cần thiết: express, mongoose và cors.

npm install express mongoose cors --save

3. Thiết lập máy chủ web Express

Trong thư mục gốc, hãy tạo một tệp server.js mới:

const express = require("express"); const cors = require("cors"); const app = express(); var corsOptions = { origin: "http://localhost:8081" }; app.use(cors(corsOptions)); // parse requests of content-type - application/json app.use(express.json()); // parse requests of content-type - application/x-www-form-urlencoded app.use(express.urlencoded({ extended: true })); // simple route app.get("/", (req, res) => { res.json({ message: "Welcome to VNFS application." }); }); // set port, listen for requests const PORT = process.env.PORT || 8080; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); });

Giải thích:

  • Nhập các module express và cors:

    • Express được sử dụng để xây dựng các Rest API
    • cors cung cấp middleware cho Express để kích hoạt CORS với các tùy chọn khác nhau.
  • Tạo một ứng dụng Express, sau đó thêm các middleware body-parser (json và urlencoded) và cors bằng cách sử dụng phương thức app.use(). Lưu ý rằng chúng ta đặt origin: http://localhost:8081.

  • Xác định một route GET đơn giản để kiểm tra.

  • Lắng nghe trên cổng 8080 để nhận các yêu cầu gửi đến.

Bây giờ hãy chạy ứng dụng bằng lệnh: node server.js Mở trình duyệt của bạn với URL http://localhost:8080/, bạn sẽ thấy kết quả như sau:


Yes, bước đầu tiên đã xong. Chúng ta sẽ làm việc với Mongoose trong phần tiếp theo.

4. Cấu hình cơ sở dữ liệu MongoDB & Mongoose

Trong thư mục ứng dụng, chúng ta tạo một thư mục config với tệp db.config.js như sau:

module.exports = { url: "mongodb://localhost:27017/vnfs_db" };

Ở bước tiếp theo, chúng ta sẽ xác định mô hình Mongoose (tutorial.model.js) trong thư mục app/models.

module.exports = mongoose => { var schema = mongoose.Schema( { title: String, description: String, published: Boolean }, { timestamps: true } ); schema.method("toJSON", function() { const { __v, _id, ...object } = this.toObject(); object.id = _id; return object; }); const Tutorial = mongoose.model("tutorial", schema); return Tutorial; };

Bây giờ hãy tạo app/models/index.js với mã sau đây:

const dbConfig = require("../config/db.config.js"); const mongoose = require("mongoose"); mongoose.Promise = global.Promise; const db = {}; db.mongoose = mongoose; db.url = dbConfig.url; db.tutorials = require("./tutorial.model.js")(mongoose); module.exports = db;

Cập nhật lại file server.js như bằng cách thêm đoạn code sau:

... const db = require("./app/models"); db.mongoose .connect(db.url, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => { console.log("Connected to the database!"); }) .catch(err => { console.log("Cannot connect to the database!", err); process.exit(); });

5. Tạo Controller

Trong thư mục app/controllers, hãy tạo tutorial.controller.js với các chức năng CRUD sau:

  • create: Tạo mới
  • findAll: Tìm tất cả
  • findOne: Tìm một
  • update: Cập nhật
  • delete: Xóa
  • deleteAll: Xóa tất cả
  • findAllPublished: Tìm tất cả Tutorial đã xuất bản
const db = require("../models"); const Tutorial = db.tutorials; // Create and Save a new Tutorial exports.create = (req, res) => { }; // Retrieve all Tutorials from the database. exports.findAll = (req, res) => { }; // Find a single Tutorial with an id exports.findOne = (req, res) => { }; // Update a Tutorial by the id in the request exports.update = (req, res) => { }; // Delete a Tutorial with the specified id in the request exports.delete = (req, res) => { }; // Delete all Tutorials from the database. exports.deleteAll = (req, res) => { }; // Find all published Tutorials exports.findAllPublished = (req, res) => { };

Tiếp tục triển khai từng functions.

Tạo một đối tượng mới

  • Tạo và Lưu một Tutorial mới:
exports.create = (req, res) => { // Validate request if (!req.body.title) { res.status(400).send({ message: "Content can not be empty!" }); return; } // Create a Tutorial const tutorial = new Tutorial({ title: req.body.title, description: req.body.description, published: req.body.published ? req.body.published : false }); // Save Tutorial in the database tutorial .save(tutorial) .then(data => { res.send(data); }) .catch(err => { res.status(500).send({ message: err.message || "Some error occurred while creating the Tutorial." }); }); };

Truy xuất các đối tượng (với điều kiện)

  • Truy xuất tất cả các Tutorial và tìm theo tiêu đề (title) từ cơ sở dữ liệu:
exports.findAll = (req, res) => { const title = req.query.title; var condition = title ? { title: { $regex: new RegExp(title), $options: "i" } } : {}; Tutorial.find(condition) .then(data => { res.send(data); }) .catch(err => { res.status(500).send({ message: err.message || "Some error occurred while retrieving tutorials." }); }); };

Chúng ta sử dụng req.query.title để lấy chuỗi truy vấn từ Request và xem nó như một điều kiện cho phương thức findAll().

Truy xuất một đối tượng duy nhất

  • Tìm một Tutorial duy nhất theo một id:
exports.findOne = (req, res) => { const id = req.params.id; Tutorial.findById(id) .then(data => { if (!data) res.status(404).send({ message: "Not found Tutorial with id " + id }); else res.send(data); }) .catch(err => { res .status(500) .send({ message: "Error retrieving Tutorial with id=" + id }); }); };

Cập nhật một đối tượng

  • Cập nhật một Tutorial được xác định bằng id trong request:
exports.update = (req, res) => { if (!req.body) { return res.status(400).send({ message: "Data to update can not be empty!" }); } const id = req.params.id; Tutorial.findByIdAndUpdate(id, req.body, { useFindAndModify: false }) .then(data => { if (!data) { res.status(404).send({ message: `Cannot update Tutorial with id=${id}. Maybe Tutorial was not found!` }); } else res.send({ message: "Tutorial was updated successfully." }); }) .catch(err => { res.status(500).send({ message: "Error updating Tutorial with id=" + id }); }); };

Xóa một đối tượng

  • Xóa Tutorial với id được chỉ định:
exports.delete = (req, res) => { const id = req.params.id; Tutorial.findByIdAndRemove(id) .then(data => { if (!data) { res.status(404).send({ message: `Cannot delete Tutorial with id=${id}. Maybe Tutorial was not found!` }); } else { res.send({ message: "Tutorial was deleted successfully!" }); } }) .catch(err => { res.status(500).send({ message: "Could not delete Tutorial with id=" + id }); }); };

Xóa tất cả đối tượng

  • Xóa tất cả Tutorial trong database:
exports.deleteAll = (req, res) => { Tutorial.deleteMany({}) .then(data => { res.send({ message: `${data.deletedCount} Tutorials were deleted successfully!` }); }) .catch(err => { res.status(500).send({ message: err.message || "Some error occurred while removing all tutorials." }); }); };

Tìm tất cả các đối tượng theo điều kiện

  • Tìm tất cả các Tutorials có published = true:
exports.findAllPublished = (req, res) => { Tutorial.find({ published: true }) .then(data => { res.send(data); }) .catch(err => { res.status(500).send({ message: err.message || "Some error occurred while retrieving tutorials." }); }); };

6. Xác định Routes

Khi một client gửi yêu cầu đến một điểm cuối sử dụng yêu cầu HTTP (GET, POST, PUT, DELETE), chúng ta cần xác định cách máy chủ sẽ phản hồi bằng cách thiết lập các route.

Dưới đây là các route của chúng ta:

  • /api/tutorials: GET, POST, DELETE
  • /api/tutorials/id GET, PUT, DELETE
  • /api/tutorials/published: GET

Hãy tạo một tệp tutorial.routes.js bên trong thư mục app/routes với nội dung như sau:

module.exports = app => { const tutorials = require("../controllers/tutorial.controller.js"); var router = require("express").Router(); // Create a new Tutorial router.post("/", tutorials.create); // Retrieve all Tutorials router.get("/", tutorials.findAll); // Retrieve all published Tutorials router.get("/published", tutorials.findAllPublished); // Retrieve a single Tutorial with id router.get("/:id", tutorials.findOne); // Update a Tutorial with id router.put("/:id", tutorials.update); // Delete a Tutorial with id router.delete("/:id", tutorials.delete); // Delete all Tutorials router.delete("/", tutorials.deleteAll); app.use('/api/tutorials', router); };

Chúng ta cũng cần thêm routes vào server.js (ngay trước app.listen()):

... require("./app/routes/tutorial.routes")(app); // set port, listen for requests const PORT = ...; app.listen(...);

7. Test APIs

Chạy project bằng câu lệnh: node server.js . Sau đó sử dụng Postman, để kiểm tra tất cả các API ở trên.

Source code: https://github.com/nv-thang/nodejs-mongo

0 Comments

Để lại một bình luận