[ Better ] Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích

Avatar admin | June 30, 2024

Dưới đây là [ Better ] Cấu trúc thư mục NODEJS API linh hoạt và cách mở rộng cấu trúc hiện tại để thêm CRUD cho đối tượng Order, Product, User tận dụng lại CURD

Table of Contents

Cấu trúc thư mục với Order

Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích
Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích
project-root/
│
├── controllers/
│   ├── AbstractController.js
│   ├── CRUDController.js
│   └── ExtendedCRUDController.js
│
├── models/
│   ├── User.js
│   ├── Product.js
│   └── Order.js
│
├── routes/
│   ├── DynamicRoutes.js
│   ├── userRoutes.js
│   ├── productRoutes.js
│   ├── orderRoutes.js
│   └── userProductRoutes.js
│
├── services/
│   ├── AbstractService.js
│   ├── CRUDService.js
│   └── ExtendedCRUDService.js
│
├── config/
│   └── serverConfig.js
│
├── servers/
│   ├── userServer.js
│   ├── productServer.js
│   ├── orderServer.js
│   └── userProductServer.js
│
├── package.json
└── README.md

Nội dung các file thêm cho Order

1. Models

1.1. Order.js
const mongoose = require('mongoose');

const orderSchema = new mongoose.Schema({
  product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product' },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  quantity: Number,
  status: String,
  orderDate: { type: Date, default: Date.now }
});

const Order = mongoose.model('Order', orderSchema);
module.exports = Order;

2. Routes

2.1. orderRoutes.js
const CRUDController = require('../controllers/CRUDController');
const CRUDService = require('../services/CRUDService');
const Order = require('../models/Order');
const createRoutes = require('./DynamicRoutes');

const orderService = new CRUDService(Order);
const orderController = new CRUDController(orderService);

const orderRoutes = createRoutes(orderController);

module.exports = orderRoutes;

3. Servers

3.1. orderServer.js
const express = require('express');
const orderRoutes = require('../routes/orderRoutes');
const config = require('../config/serverConfig');
const mongoose = require('mongoose');

const app = express();
app.use(express.json());
app.use('/api/orders', orderRoutes);

mongoose.connect(config.dbConnectionString, { useNewUrlParser: true, useUnifiedTopology: true });

app.listen(config.port, () => {
  console.log(`Order server is running on port ${config.port}`);
});

package.json

Cập nhật tệp package.json để thêm lệnh khởi động cho Order server:

{
  "scripts": {
    "start": "node servers/userServer.js",
    "start:product": "node servers/productServer.js",
    "start:order": "node servers/orderServer.js",
    "start:userProduct": "node servers/userProductServer.js"
  }
}

README.md

Cập nhật tệp README.md để phản ánh sự bổ sung của Order.

# Dynamic CRUD Application

This is a dynamic CRUD application built using Express.js and MongoDB. It supports creating, reading, updating, and deleting resources, with dynamic route handling for different models.

## Getting Started

### Prerequisites

- Node.js
- MongoDB

### Installing

1. Clone the repository:

```bash
git clone <repository-url>
cd project-root
  1. Install dependencies:
npm install
  1. Set up the environment variables:

Create a .env file in the root directory and add the following:

PORT=3000
DB_CONNECTION_STRING=mongodb://localhost:27017/mydatabase
  1. Start the servers:
npm start
npm run start:product
npm run start:order
npm run start:userProduct

Project Structure

  • controllers/: Contains controller classes for handling CRUD operations.
  • models/: Contains Mongoose models for different resources.
  • routes/: Contains route definitions for different resources.
  • services/: Contains service classes for business logic and data manipulation.
  • config/: Contains configuration files.
  • servers/: Contains server files for starting the application.

Để tổ chức các thư mục và tệp tin cho từng đối tượng (User, Product, Order) một cách rõ ràng, bạn có thể tạo các thư mục riêng biệt cho từng đối tượng.
Dưới đây là cấu trúc thư mục được tổ chức lại:

Cấu trúc thư mục được tổ chức lại

project-root/
│
├── controllers/
│   ├── AbstractController.js
│   ├── user/
│   │   └── UserController.js
│   ├── product/
│   │   └── ProductController.js
│   └── order/
│       └── OrderController.js
│
├── models/
│   ├── User.js
│   ├── Product.js
│   └── Order.js
│
├── routes/
│   ├── DynamicRoutes.js
│   ├── user/
│   │   └── userRoutes.js
│   ├── product/
│   │   └── productRoutes.js
│   └── order/
│       └── orderRoutes.js
│
├── services/
│   ├── AbstractService.js
│   ├── user/
│   │   └── UserService.js
│   ├── product/
│   │   └── ProductService.js
│   └── order/
│       └── OrderService.js
│
├── config/
│   └── serverConfig.js
│
├── servers/
│   ├── userServer.js
│   ├── productServer.js
│   └── orderServer.js
│
├── package.json
└── README.md

Nội dung các file

1. Controllers

1.1. AbstractController.js
class AbstractController {
  constructor(service) {
    if (new.target === AbstractController) {
      throw new TypeError("Cannot construct AbstractController instances directly");
    }
    this.service = service;
  }

  async create(req, res) {
    throw new Error("Method 'create()' must be implemented.");
  }

  async getAll(req, res) {
    throw new Error("Method 'getAll()' must be implemented.");
  }

  async getById(req, res) {
    throw new Error("Method 'getById()' must be implemented.");
  }

  async update(req, res) {
    throw new Error("Method 'update()' must be implemented.");
  }

  async delete(req, res) {
    throw new Error("Method 'delete()' must be implemented.");
  }
}

module.exports = AbstractController;
1.2. user/UserController.js
const AbstractController = require('../AbstractController');

class UserController extends AbstractController {
  constructor(service) {
    super(service);
  }

  async create(req, res) {
    try {
      const data = await this.service.create(req.body);
      res.status(201).json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getAll(req, res) {
    try {
      const data = await this.service.getAll();
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getById(req, res) {
    try {
      const data = await this.service.getById(req.params.id);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async update(req, res) {
    try {
      const data = await this.service.update(req.params.id, req.body);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async delete(req, res) {
    try {
      const success = await this.service.delete(req.params.id);
      if (success) {
        res.status(204).end();
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
}

module.exports = UserController;
1.3. product/ProductController.js
const AbstractController = require('../AbstractController');

class ProductController extends AbstractController {
  constructor(service) {
    super(service);
  }

  async create(req, res) {
    try {
      const data = await this.service.create(req.body);
      res.status(201).json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getAll(req, res) {
    try {
      const data = await this.service.getAll();
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getById(req, res) {
    try {
      const data = await this.service.getById(req.params.id);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async update(req, res) {
    try {
      const data = await this.service.update(req.params.id, req.body);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async delete(req, res) {
    try {
      const success = await this.service.delete(req.params.id);
      if (success) {
        res.status(204).end();
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
}

module.exports = ProductController;
1.4. order/OrderController.js
const AbstractController = require('../AbstractController');

class OrderController extends AbstractController {
  constructor(service) {
    super(service);
  }

  async create(req, res) {
    try {
      const data = await this.service.create(req.body);
      res.status(201).json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getAll(req, res) {
    try {
      const data = await this.service.getAll();
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getById(req, res) {
    try {
      const data = await this.service.getById(req.params.id);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async update(req, res) {
    try {
      const data = await this.service.update(req.params.id, req.body);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async delete(req, res) {
    try {
      const success = await this.service.delete(req.params.id);
      if (success) {
        res.status(204).end();
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
}

module.exports = OrderController;

2. Routes

2.1. DynamicRoutes.js
const express = require('express');

function createRoutes(controller) {
  const router = express.Router();

  router.post('/', (req, res) => controller.create(req, res));
  router.get('/', (req, res) => controller.getAll(req, res));
  router.get('/:id', (req, res) => controller.getById(req, res));
  router.put('/:id', (req, res) => controller.update(req, res));
  router.delete('/:id', (req, res) => controller.delete(req, res));

  return router;
}

module.exports = createRoutes;
2.2. user/userRoutes.js
const UserController = require('../../controllers/user/UserController');
const UserService = require('../../services/user/UserService');
const User = require('../../models/User');
const createRoutes = require('../DynamicRoutes');

const userService = new UserService(User);
const userController = new UserController(userService);

const userRoutes = createRoutes(userController);

module.exports = userRoutes;
2.3. product/productRoutes.js
const ProductController = require('../../controllers/product/ProductController');
const ProductService = require('../../services/product/ProductService');
const Product = require('../../models/Product');
const createRoutes = require('../DynamicRoutes');

const productService = new ProductService(Product);
const productController = new ProductController(productService);

const productRoutes = createRoutes(productController);

module.exports = productRoutes;
2.4. order/orderRoutes.js
const OrderController = require('../../controllers/order/OrderController');
const OrderService = require('../../services/order/OrderService');
const Order = require('../../models/Order');
const createRoutes = require('../DynamicRoutes');

const orderService = new OrderService(Order);
const orderController = new OrderController(orderService);

const orderRoutes = createRoutes(orderController);

module.exports = orderRoutes;

3. Services

3.1. AbstractService.js
class AbstractService {
  constructor(model) {
    if (new.target === AbstractService) {
      throw new TypeError("Cannot construct AbstractService instances directly");
    }
    this.model = model;
  }

  async create(data) {
    throw new Error("Method 'create()' must be implemented.");
  }

  async getAll() {
    throw new Error("Method 'getAll()' must be implemented.");
  }

  async getById(id) {
    throw new Error("Method 'getById()' must be implemented.");
  }

  async update(id, data) {
    throw new Error("Method 'update()' must be implemented.");
  }

  async delete(id) {
    throw new Error("Method 'delete()' must be implemented.");
  }
}

module.exports = AbstractService;
3.2. user/UserService.js
const AbstractService = require('../AbstractService');

class UserService extends AbstractService {
  constructor(model) {
    super(model);
  }

  async create(data) {
    return await this.model.create(data);
  }

  async getAll() {
    return await this.model.find();
  }

  async getById(id) {
    return await this.model.findById(id);
  }

  async update(id, data) {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id) {
    const result = await this.model.findByIdAndDelete(id);
    return result !== null;
  }
}

module.exports = UserService;
3.3. product/ProductService.js
const AbstractService = require('../AbstractService');

class ProductService extends AbstractService {
  constructor(model) {
    super(model);
  }

  async create(data) {
    return await this.model.create(data);
  }

  async getAll() {
    return await this.model.find();
  }

  async getById(id) {
    return await this.model.findById(id);
  }

  async update(id, data) {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id) {
    const result = await this.model.findByIdAndDelete(id);
    return result !== null;
  }
}

module.exports = ProductService;
3.4. order/OrderService.js
const AbstractService = require('../AbstractService');

class OrderService extends AbstractService {
  constructor(model) {
    super(model);
  }

  async create(data) {
    return await this.model.create(data);
  }

  async getAll() {
    return await this.model.find().populate('product user');
  }

  async getById(id) {
    return await this.model.findById(id).populate('product user');
  }

  async update(id, data) {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id) {
    const result = await this.model.findByIdAndDelete(id);
    return result !== null;
  }
}

module.exports = OrderService;

4. Servers

4.1. userServer.js
const express = require('express');
const userRoutes = require('../routes/user/userRoutes');
const config = require('../config/serverConfig');
const mongoose = require('mongoose');

const app = express();
app.use(express.json());
app.use('/api/users', userRoutes);

mongoose.connect(config.dbConnectionString, { useNewUrlParser: true, useUnifiedTopology: true });

app.listen(config.port, () => {
  console.log(`User server is running on port ${config.port}`);
});
4.2. productServer.js
const express = require('express');
const productRoutes = require('../routes/product/productRoutes');
const config = require('../config/serverConfig');
const mongoose = require('mongoose');

const app = express();
app.use(express.json());
app.use('/api/products', productRoutes);

mongoose.connect(config.dbConnectionString, { useNewUrlParser: true, useUnifiedTopology: true });

app.listen(config.port, () => {
  console.log(`Product server is running on port ${config.port}`);
});
4.3. orderServer.js
const express = require('express');
const orderRoutes = require('../routes/order/orderRoutes');
const config = require('../config/serverConfig');
const mongoose = require('mongoose');

const app = express();
app.use(express.json());
app.use('/api/orders', orderRoutes);

mongoose.connect(config.dbConnectionString, { useNewUrlParser: true, useUnifiedTopology: true });

app.listen(config.port, () => {
  console.log(`Order server is running on port ${config.port}`);
});

package.json

Cập nhật tệp package.json để thêm lệnh khởi động cho Order server:

{
  "scripts": {
    "start": "node servers/userServer.js",
    "start:product": "node servers/productServer.js",
    "start:order": "node servers/orderServer.js"
  }
}

README.md

Cập nhật tệp README.md để phản ánh sự bổ sung của Order.

# Dynamic CRUD Application

This is a dynamic CRUD application built using Express.js and MongoDB. It supports creating, reading, updating, and deleting resources, with dynamic route handling for different models.

## Getting Started

### Prerequisites

- Node.js
- MongoDB

### Installing

1. Clone the repository:

```bash
git clone <repository-url>
cd project-root
  1. Install dependencies:
npm install
  1. Set up the environment variables:

Create a .env file in the root directory and add the following:

PORT=3000
DB_CONNECTION_STRING=mongodb://localhost:27017/mydatabase
  1. Start the servers:
npm start
npm run start:product
npm run start:order

Project Structure

  • controllers/: Contains controller classes for handling CRUD operations.
    • user/: Contains user-specific controllers.
    • product/: Contains product-specific controllers.
    • order/: Contains order-specific controllers.
  • user/: Contains user-specific controllers.
  • product/: Contains product-specific controllers.
  • order/: Contains order-specific controllers.
  • models/: Contains Mongoose models for different resources.
  • routes/: Contains route definitions for different resources.
    • user/: Contains user-specific routes.
    • product/: Contains product-specific routes.
    • order/: Contains order-specific routes.
  • user/: Contains user-specific routes.
  • product/: Contains product-specific routes.
  • order/: Contains order-specific routes.
  • services/: Contains service classes for business logic and data manipulation.
    • user/: Contains user-specific services.
    • product/: Contains product-specific services.
    • order/: Contains order-specific services.
  • user/: Contains user-specific services.
  • product/: Contains product-specific services.
  • order/: Contains order-specific services.
  • config/: Contains configuration files.
  • servers/: Contains server files for starting the application.
  • user/: Contains user-specific controllers.
  • product/: Contains product-specific controllers.
  • order/: Contains order-specific controllers.
  • user/: Contains user-specific routes.
  • product/: Contains product-specific routes.
  • order/: Contains order-specific routes.
  • user/: Contains user-specific services.
  • product/: Contains product-specific services.
  • order/: Contains order-specific services.

Authors

  • Your Name

License

This project is licensed under the MIT License.

Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích
Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích

Để giải quyết yêu cầu của bạn, chúng ta có thể xây dựng một thư viện (module) cho các chức năng CRUD mà bạn có thể tái sử dụng và mở rộng một cách dễ dàng.
Đây là một phương pháp hiệu quả để giảm thiểu việc lặp lại mã và tăng tính linh hoạt của ứng dụng.

Thiết kế một thư viện CRUD

Chúng ta sẽ tạo ra một thư viện có thể xử lý các chức năng CRUD chung cho các mô hình khác nhau (ví dụ: User, Product, Order).
Thư viện này sẽ gồm các thành phần sau:

1. AbstractController.js

Đây là lớp controller trừu tượng mà các controller cụ thể sẽ kế thừa.
Nó định nghĩa các phương thức cơ bản như create, getAll, getById, update, delete.

// controllers/AbstractController.js

class AbstractController {
  constructor(service) {
    this.service = service;
  }

  async create(req, res) {
    try {
      const data = await this.service.create(req.body);
      res.status(201).json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getAll(req, res) {
    try {
      const data = await this.service.getAll();
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getById(req, res) {
    try {
      const data = await this.service.getById(req.params.id);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async update(req, res) {
    try {
      const data = await this.service.update(req.params.id, req.body);
      if (data) {
        res.json(data);
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async delete(req, res) {
    try {
      const success = await this.service.delete(req.params.id);
      if (success) {
        res.status(204).end();
      } else {
        res.status(404).json({ error: 'Not Found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
}

module.exports = AbstractController;

2. AbstractService.js

Lớp service trừu tượng định nghĩa các phương thức CRUD cơ bản.

// services/AbstractService.js

class AbstractService {
  constructor(model) {
    this.model = model;
  }

  async create(data) {
    return await this.model.create(data);
  }

  async getAll() {
    return await this.model.find();
  }

  async getById(id) {
    return await this.model.findById(id);
  }

  async update(id, data) {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id) {
    const result = await this.model.findByIdAndDelete(id);
    return result !== null;
  }
}

module.exports = AbstractService;

3. Các Controllers Cụ thể (User, Product, Order)

Các controller cụ thể kế thừa từ AbstractController và sử dụng AbstractService để thực hiện các thao tác CRUD cho từng mô hình cụ thể.

// controllers/UserController.js

const AbstractController = require('./AbstractController');

class UserController extends AbstractController {
  constructor(service) {
    super(service);
  }
}

module.exports = UserController;
// controllers/ProductController.js

const AbstractController = require('./AbstractController');

class ProductController extends AbstractController {
  constructor(service) {
    super(service);
  }
}

module.exports = ProductController;
// controllers/OrderController.js

const AbstractController = require('./AbstractController');

class OrderController extends AbstractController {
  constructor(service) {
    super(service);
  }
}

module.exports = OrderController;

4. Các Services Cụ thể (User, Product, Order)

Các service cụ thể kế thừa từ AbstractService và thực hiện các thao tác CRUD cho từng mô hình cụ thể.

// services/UserService.js

const AbstractService = require('./AbstractService');
const User = require('../models/User');

class UserService extends AbstractService {
  constructor() {
    super(User);
  }
}

module.exports = UserService;
// services/ProductService.js

const AbstractService = require('./AbstractService');
const Product = require('../models/Product');

class ProductService extends AbstractService {
  constructor() {
    super(Product);
  }
}

module.exports = ProductService;
// services/OrderService.js

const AbstractService = require('./AbstractService');
const Order = require('../models/Order');

class OrderService extends AbstractService {
  constructor() {
    super(Order);
  }
}

module.exports = OrderService;

5. Routes

Bạn có thể sử dụng một hàm helper để tạo các routes tự động dựa trên controller cụ thể.

// routes/DynamicRoutes.js

const express = require('express');

function createRoutes(controller) {
  const router = express.Router();

  router.post('/', (req, res) => controller.create(req, res));
  router.get('/', (req, res) => controller.getAll(req, res));
  router.get('/:id', (req, res) => controller.getById(req, res));
  router.put('/:id', (req, res) => controller.update(req, res));
  router.delete('/:id', (req, res) => controller.delete(req, res));

  return router;
}

module.exports = createRoutes;

6. Thêm vào Servers

Các server sẽ chỉ cần sử dụng các controllers và routes tương ứng.

// servers/userServer.js

const express = require('express');
const config = require('../config/serverConfig');
const mongoose = require('mongoose');
const UserController = require('../controllers/UserController');
const UserService = require('../services/UserService');
const createUserRoutes = require('../routes/DynamicRoutes');

const app = express();
app.use(express.json());

const userService = new UserService();
const userController = new UserController(userService);
const userRoutes = createUserRoutes(userController);

app.use('/api/users', userRoutes);

mongoose.connect(config.dbConnectionString, { useNewUrlParser: true, useUnifiedTopology: true });

app.listen(config.port, () => {
  console.log(`User server is running on port ${config.port}`);
});

Tương tự, bạn sẽ cấu hình các servers cho Product và Order bằng cách thay thế UserController, UserService và các routes tương ứng.

7. Cấu hình package.json

Cập nhật scripts để khởi động các servers.

{
  "scripts": {
    "start:user": "node servers/userServer.js",
    "start:product": "node servers/productServer.js",
    "start:order": "node servers/orderServer.js"
  }
}

Lợi ích

  • Tái sử dụng mã: Bạn có thể sử dụng lại các controllers và services cho nhiều mô hình khác nhau một cách dễ dàng.
  • Mở rộng dễ dàng: Để mở rộng chức năng, bạn chỉ cần tạo một controller và service mới và kết nối chúng với routes tương ứng.
  • Tính linh hoạt cao: Việc sử dụng các lớp trừu tượng và hàm helper giúp cho việc thêm mới và thay đổi các thành phần trở nên đơn giản và nhanh chóng.

Với cách tiếp cận này, bạn có thể tổ chức mã nguồn một cách rõ ràng và giảm thiểu sự phụ thuộc giữa các phần của ứng dụng, giúp dễ dàng bảo trì và mở rộng trong tương lai.

Dưới đây là cấu trúc thư mục và các tệp tin tương ứng để triển khai một ứng dụng có tính tái sử dụng cao, sử dụng các module và thư viện để quản lý các chức năng CRUD cho các đối tượng User, Product, và Order.

Cấu trúc Thư mục

project-root/
│
├── config/
│   └── serverConfig.js
│
├── controllers/
│   ├── AbstractController.js
│   ├── OrderController.js
│   ├── ProductController.js
│   └── UserController.js
│
├── models/
│   ├── Order.js
│   ├── Product.js
│   └── User.js
│
├── routes/
│   ├── DynamicRoutes.js
│   ├── order/
│   │   └── orderRoutes.js
│   ├── product/
│   │   └── productRoutes.js
│   └── user/
│       └── userRoutes.js
│
├── services/
│   ├── AbstractService.js
│   ├── OrderService.js
│   ├── ProductService.js
│   └── UserService.js
│
└── servers/
    ├── orderServer.js
    ├── productServer.js
    └── userServer.js

Giải thích cấu trúc thư mục và các tệp tin

  1. config/

    • serverConfig.js: Chứa cấu hình của server, ví dụ như chuỗi kết nối đến cơ sở dữ liệu.
  2. serverConfig.js: Chứa cấu hình của server, ví dụ như chuỗi kết nối đến cơ sở dữ liệu.
  3. controllers/

    • AbstractController.js: Lớp controller trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
    • UserController.js, ProductController.js, OrderController.js: Các controller cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractController và xử lý logic cụ thể cho từng đối tượng.
  4. AbstractController.js: Lớp controller trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
  5. UserController.js, ProductController.js, OrderController.js: Các controller cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractController và xử lý logic cụ thể cho từng đối tượng.
  6. models/

    • User.js, Product.js, Order.js: Định nghĩa các schema và model cho các đối tượng User, Product và Order sử dụng Mongoose.
  7. User.js, Product.js, Order.js: Định nghĩa các schema và model cho các đối tượng User, Product và Order sử dụng Mongoose.
  8. routes/

    • DynamicRoutes.js: Hàm helper để tạo các routes tự động dựa trên controller cụ thể.
    • user/, product/, order/: Các thư mục con chứa các tệp tin route cho từng đối tượng tương ứng (userRoutes.js, productRoutes.js, orderRoutes.js).
  9. DynamicRoutes.js: Hàm helper để tạo các routes tự động dựa trên controller cụ thể.
  10. user/, product/, order/: Các thư mục con chứa các tệp tin route cho từng đối tượng tương ứng (userRoutes.js, productRoutes.js, orderRoutes.js).
  11. services/

    • AbstractService.js: Lớp service trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
    • UserService.js, ProductService.js, OrderService.js: Các service cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractService và thực hiện các thao tác với cơ sở dữ liệu.
  12. AbstractService.js: Lớp service trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
  13. UserService.js, ProductService.js, OrderService.js: Các service cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractService và thực hiện các thao tác với cơ sở dữ liệu.
  14. servers/

    • userServer.js, productServer.js, orderServer.js: Các tệp server khởi động cho User, Product và Order servers. Sử dụng Express để định nghĩa các routes và kết nối tới cơ sở dữ liệu.
  15. userServer.js, productServer.js, orderServer.js: Các tệp server khởi động cho User, Product và Order servers. Sử dụng Express để định nghĩa các routes và kết nối tới cơ sở dữ liệu.

config/

  • serverConfig.js: Chứa cấu hình của server, ví dụ như chuỗi kết nối đến cơ sở dữ liệu.

controllers/

  • AbstractController.js: Lớp controller trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
  • UserController.js, ProductController.js, OrderController.js: Các controller cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractController và xử lý logic cụ thể cho từng đối tượng.

models/

  • User.js, Product.js, Order.js: Định nghĩa các schema và model cho các đối tượng User, Product và Order sử dụng Mongoose.

routes/

  • DynamicRoutes.js: Hàm helper để tạo các routes tự động dựa trên controller cụ thể.
  • user/, product/, order/: Các thư mục con chứa các tệp tin route cho từng đối tượng tương ứng (userRoutes.js, productRoutes.js, orderRoutes.js).

services/

  • AbstractService.js: Lớp service trừu tượng định nghĩa các phương thức CRUD cơ bản như create, getAll, getById, update, delete.
  • UserService.js, ProductService.js, OrderService.js: Các service cụ thể cho các đối tượng User, Product và Order. Kế thừa từ AbstractService và thực hiện các thao tác với cơ sở dữ liệu.

servers/

  • userServer.js, productServer.js, orderServer.js: Các tệp server khởi động cho User, Product và Order servers. Sử dụng Express để định nghĩa các routes và kết nối tới cơ sở dữ liệu.

Tóm tắt

Cấu trúc thư mục và các tệp tin được tổ chức theo mô hình MVC (Model-View-Controller), với các thành phần cụ thể như controllers, services, models, và routes.
Mỗi đối tượng (User, Product, Order) có các controllers và services riêng biệt để quản lý các chức năng CRUD, và các routes cũng được phân tách để dễ dàng quản lý và mở rộng.
Bằng cách này, ứng dụng của bạn có tính tái sử dụng cao và dễ dàng mở rộng khi cần thiết.

Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích
Cấu trúc thư mục NODEJS API linh hoạt cho CURD và 10 lợi ích

Nếu bạn muốn mở rộng chức năng của đối tượng User để bao gồm nhiều hơn chỉ các hoạt động CRUD và có các chức năng liên quan tương tác khác, bạn có thể thực hiện như sau:

1. Mở rộng Service và Controller của User

a. Thêm các phương thức vào UserService

Ví dụ, bạn có thể thêm các phương thức như getUserByUsername, updatePassword, addToFavorites, getFavorites, addRole, removeRole, getRoles, vv.
vào UserService.
Đây là các hành động tùy chỉnh hoặc mở rộng mà bạn muốn thực hiện với đối tượng User.

// services/UserService.js

const AbstractService = require('./AbstractService');
const User = require('../models/User');

class UserService extends AbstractService {
  constructor() {
    super(User);
  }

  async getUserByUsername(username) {
    return await this.model.findOne({ username });
  }

  async updatePassword(userId, newPassword) {
    return await this.model.findByIdAndUpdate(userId, { password: newPassword }, { new: true });
  }

  async addToFavorites(userId, productId) {
    const user = await this.model.findById(userId);
    if (!user) throw new Error('User not found');
    
    if (!user.favorites.includes(productId)) {
      user.favorites.push(productId);
      await user.save();
    }
    
    return user;
  }

  async getFavorites(userId) {
    const user = await this.model.findById(userId).populate('favorites');
    if (!user) throw new Error('User not found');

    return user.favorites;
  }

  async addRole(userId, role) {
    const user = await this.model.findById(userId);
    if (!user) throw new Error('User not found');
    
    if (!user.roles.includes(role)) {
      user.roles.push(role);
      await user.save();
    }
    
    return user;
  }

  async removeRole(userId, role) {
    const user = await this.model.findById(userId);
    if (!user) throw new Error('User not found');
    
    user.roles = user.roles.filter(r => r !== role);
    await user.save();
    
    return user;
  }

  async getRoles(userId) {
    const user = await this.model.findById(userId);
    if (!user) throw new Error('User not found');

    return user.roles;
  }
}

module.exports = UserService;

b. Mở rộng UserController

Cập nhật UserController để bao gồm các phương thức điều khiển mới để xử lý các yêu cầu liên quan tới User.

// controllers/UserController.js

const AbstractController = require('./AbstractController');
const UserService = require('../services/UserService');

class UserController extends AbstractController {
  constructor() {
    super(new UserService());
  }

  async getUserByUsername(req, res) {
    try {
      const username = req.params.username;
      const user = await this.service.getUserByUsername(username);
      if (user) {
        res.json(user);
      } else {
        res.status(404).json({ error: 'User not found' });
      }
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async updatePassword(req, res) {
    try {
      const userId = req.params.id;
      const newPassword = req.body.password;
      const user = await this.service.updatePassword(userId, newPassword);
      res.json(user);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async addToFavorites(req, res) {
    try {
      const userId = req.params.id;
      const productId = req.body.productId;
      const user = await this.service.addToFavorites(userId, productId);
      res.json(user);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getFavorites(req, res) {
    try {
      const userId = req.params.id;
      const favorites = await this.service.getFavorites(userId);
      res.json(favorites);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async addRole(req, res) {
    try {
      const userId = req.params.id;
      const role = req.body.role;
      const user = await this.service.addRole(userId, role);
      res.json(user);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async removeRole(req, res) {
    try {
      const userId = req.params.id;
      const role = req.body.role;
      const user = await this.service.removeRole(userId, role);
      res.json(user);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }

  async getRoles(req, res) {
    try {
      const userId = req.params.id;
      const roles = await this.service.getRoles(userId);
      res.json(roles);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
}

module.exports = UserController;

2. Cập nhật Routes

Cập nhật userRoutes.js để bao gồm các routes mới cho các phương thức tương tác liên quan tới User.

// routes/user/userRoutes.js

const express = require('express');
const UserController = require('../../controllers/UserController');
const createUserRoutes = require('../DynamicRoutes');

const controller = new UserController();
const userRoutes = createUserRoutes(controller);

userRoutes.get('/username/:username', (req, res) => controller.getUserByUsername(req, res));
userRoutes.put('/:id/password', (req, res) => controller.updatePassword(req, res));
userRoutes.post('/:id/favorites', (req, res) => controller.addToFavorites(req, res));
userRoutes.get('/:id/favorites', (req, res) => controller.getFavorites(req, res));
userRoutes.post('/:id/roles', (req, res) => controller.addRole(req, res));
userRoutes.delete('/:id/roles', (req, res) => controller.removeRole(req, res));
userRoutes.get('/:id/roles', (req, res) => controller.getRoles(req, res));

module.exports = userRoutes;

3. Thêm tính năng mới

Nếu bạn muốn thêm tính năng khác, bạn có thể lặp lại quy trình tương tự:

  • Thêm phương thức vào UserService.
  • Thêm phương thức điều khiển tương ứng vào UserController.
  • Cập nhật userRoutes.js để đăng ký route cho phương thức mới.

Điều này giúp bạn duy trì sự tổ chức rõ ràng và tái sử dụng mã một cách hiệu quả trong ứng dụng của mình.

Để giảm sự lặp lại của mã try-catch và tạo một base class để xử lý các lỗi chung trong các controller, bạn có thể áp dụng một phương pháp gọi là middleware trong Express.
Middleware cho phép bạn định nghĩa một hàm xử lý lỗi chung và tái sử dụng nó trên các route khác nhau một cách dễ dàng.

Dưới đây là cách bạn có thể cải thiện mã của UserController và các controllers khác bằng cách sử dụng middleware để xử lý lỗi:

1. Middleware xử lý lỗi chung

Bạn có thể tạo một middleware xử lý lỗi chung và sử dụng nó để bọc các phương thức điều khiển của controller.
Đây là ví dụ cụ thể:

// middleware/errorHandler.js

function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).json({ error: err.message });
}

module.exports = errorHandler;

2. Cập nhật các Controllers để sử dụng Middleware

Các controllers sẽ bao gồm các phương thức và sử dụng middleware để xử lý lỗi chung.
Ví dụ:

// controllers/UserController.js

const AbstractController = require('./AbstractController');
const UserService = require('../services/UserService');

class UserController extends AbstractController {
  constructor() {
    super(new UserService());
  }

  async getUserByUsername(req, res) {
    const username = req.params.username;
    const user = await this.service.getUserByUsername(username);
    if (!user) {
      res.status(404).json({ error: 'User not found' });
      return;
    }
    res.json(user);
  }

  async updatePassword(req, res) {
    const userId = req.params.id;
    const newPassword = req.body.password;
    const user = await this.service.updatePassword(userId, newPassword);
    res.json(user);
  }

  async addToFavorites(req, res) {
    const userId = req.params.id;
    const productId = req.body.productId;
    const user = await this.service.addToFavorites(userId, productId);
    res.json(user);
  }

  async getFavorites(req, res) {
    const userId = req.params.id;
    const favorites = await this.service.getFavorites(userId);
    res.json(favorites);
  }

  async addRole(req, res) {
    const userId = req.params.id;
    const role = req.body.role;
    const user = await this.service.addRole(userId, role);
    res.json(user);
  }

  async removeRole(req, res) {
    const userId = req.params.id;
    const role = req.body.role;
    const user = await this.service.removeRole(userId, role);
    res.json(user);
  }

  async getRoles(req, res) {
    const userId = req.params.id;
    const roles = await this.service.getRoles(userId);
    res.json(roles);
  }
}

module.exports = UserController;

3. Kết nối Middleware vào ứng dụng Express

Cuối cùng, bạn cần kết nối middleware xử lý lỗi chung vào ứng dụng Express của bạn:

// app.js hoặc server.js

const express = require('express');
const errorHandler = require('./middleware/errorHandler');
const userRoutes = require('./routes/user/userRoutes');
// Import các routes và middleware khác cần thiết

const app = express();

app.use(express.json());

// Sử dụng middleware xử lý lỗi chung
app.use(errorHandler);

// Đăng ký các routes
app.use('/api/users', userRoutes);
// Đăng ký các routes khác tương tự

// Khởi động server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Lợi ích của phương pháp này:

  • Tái sử dụng mã: Bạn không cần phải lặp lại các lệnh try-catch trong từng phương thức điều khiển, mà chỉ cần xử lý lỗi một cách chung chung trong middleware.
  • Giảm độ phức tạp của controller: Các controller trở nên gọn gàng hơn với mã xử lý logic chính, không phải lo lắng về việc xử lý lỗi.
  • Quản lý lỗi hiệu quả: Middleware xử lý lỗi giúp bạn log và xử lý các lỗi một cách thống nhất trong toàn bộ ứng dụng.

Qua đó, bạn có thể giảm thiểu sự lặp lại mã và cải thiện quản lý lỗi trong ứng dụng của mình.

Để giảm sự lặp lại trong việc kiểm tra sự tồn tại của người dùng (user existence check), bạn có thể sử dụng một middleware hoặc một hàm helper để thực hiện điều này một cách hiệu quả và tái sử dụng được trong toàn bộ ứng dụng.
Dưới đây là một phương pháp để làm điều này:

Sử dụng Middleware để Kiểm tra Sự Tồn Tại của User

Bạn có thể viết một middleware đơn giản để kiểm tra sự tồn tại của user dựa trên userId được truyền từ các request.

1. Middleware kiểm tra sự tồn tại của User

// middleware/checkUserExists.js

const User = require('../models/User');

async function checkUserExists(req, res, next) {
  const userId = req.params.id; // Lấy userId từ request params

  try {
    const user = await User.findById(userId);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    req.user = user; // Lưu user vào req để có thể sử dụng trong các xử lý tiếp theo
    next();
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: 'Server error' });
  }
}

module.exports = checkUserExists;

2. Sử dụng Middleware trong các Controllers

Sau khi có middleware checkUserExists, bạn có thể áp dụng nó trong các routes hoặc controllers mà bạn cần kiểm tra sự tồn tại của user.

Ví dụ trong UserController:

// controllers/UserController.js

const AbstractController = require('./AbstractController');
const UserService = require('../services/UserService');
const checkUserExists = require('../middleware/checkUserExists');

class UserController extends AbstractController {
  constructor() {
    super(new UserService());
  }

  async getUser(req, res) {
    res.json(req.user); // Middleware đã lưu user vào req.user nếu tồn tại
  }

  async updateUser(req, res) {
    const userId = req.params.id;
    const newData = req.body;

    try {
      // Cập nhật thông tin user
      const updatedUser = await this.service.update(userId, newData);
      res.json(updatedUser);
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }

  async deleteUser(req, res) {
    const userId = req.params.id;

    try {
      // Xóa user
      await this.service.delete(userId);
      res.json({ message: 'User deleted successfully' });
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }
}

module.exports = UserController;

3. Đăng ký Middleware trong Routes

Cuối cùng, bạn cần đăng ký middleware checkUserExists vào các routes mà bạn muốn kiểm tra sự tồn tại của user.

// routes/user/userRoutes.js

const express = require('express');
const UserController = require('../../controllers/UserController');
const checkUserExists = require('../../middleware/checkUserExists');

const controller = new UserController();
const userRoutes = express.Router();

userRoutes.get('/:id', checkUserExists, (req, res) => controller.getUser(req, res));
userRoutes.put('/:id', checkUserExists, (req, res) => controller.updateUser(req, res));
userRoutes.delete('/:id', checkUserExists, (req, res) => controller.deleteUser(req, res));

module.exports = userRoutes;

Lợi ích của phương pháp này:

  • Tái sử dụng mã: Middleware checkUserExists giúp bạn kiểm tra sự tồn tại của user một cách hiệu quả và tái sử dụng được trong nhiều routes khác nhau.
  • Giảm sự lặp lại: Bạn không cần phải lặp lại mã kiểm tra sự tồn tại của user trong từng phương thức điều khiển (controller).
  • Quản lý mã một cách rõ ràng: Middleware giúp mã của bạn trở nên gọn gàng hơn và dễ quản lý hơn.

Qua đó, việc sử dụng middleware để kiểm tra sự tồn tại của user là một cách hiệu quả để giảm sự lặp lại của mã trong ứng dụng của bạn.

Dưới đây là tóm tắt các phương pháp đã xử lý để tạo ra một ứng dụng Node.js với chức năng CRUD và khả năng mở rộng, bao gồm cả việc xử lý lỗi và kiểm tra sự tồn tại của user một cách hiệu quả:

1. Tạo cấu trúc thư mục rõ ràng và phân chia module hợp lý

Chúng ta đã thiết kế một cấu trúc thư mục rõ ràng để quản lý các thành phần khác nhau của ứng dụng theo mô hình MVC (Model-View-Controller):

project-root/
│
├── config/
│   └── serverConfig.js
│
├── controllers/
│   ├── AbstractController.js
│   ├── OrderController.js
│   ├── ProductController.js
│   └── UserController.js
│
├── middleware/
│   ├── errorHandler.js
│   └── checkUserExists.js
│
├── models/
│   ├── Order.js
│   ├── Product.js
│   └── User.js
│
├── routes/
│   ├── DynamicRoutes.js
│   ├── order/
│   │   └── orderRoutes.js
│   ├── product/
│   │   └── productRoutes.js
│   └── user/
│       └── userRoutes.js
│
├── services/
│   ├── AbstractService.js
│   ├── OrderService.js
│   ├── ProductService.js
│   └── UserService.js
│
└── servers/
    ├── orderServer.js
    ├── productServer.js
    └── userServer.js

2. Sử dụng lớp trừu tượng để giảm sự lặp lại của mã CRUD

Tạo các lớp trừu tượng (AbstractService và AbstractController) để định nghĩa các phương thức CRUD cơ bản, sau đó các lớp cụ thể như UserService và UserController sẽ kế thừa và mở rộng khi cần thiết:

// services/AbstractService.js
class AbstractService {
  constructor(model) {
    this.model = model;
  }

  async create(data) {
    return await this.model.create(data);
  }

  async getAll() {
    return await this.model.find();
  }

  async getById(id) {
    return await this.model.findById(id);
  }

  async update(id, data) {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id) {
    return await this.model.findByIdAndDelete(id);
  }
}

// controllers/AbstractController.js
class AbstractController {
  constructor(service) {
    this.service = service;
  }

  async create(req, res) {
    try {
      const data = req.body;
      const result = await this.service.create(data);
      res.json(result);
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }

  async getAll(req, res) {
    try {
      const result = await this.service.getAll();
      res.json(result);
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }

  async getById(req, res) {
    try {
      const id = req.params.id;
      const result = await this.service.getById(id);
      if (!result) {
        return res.status(404).json({ error: 'Not found' });
      }
      res.json(result);
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }

  async update(req, res) {
    try {
      const id = req.params.id;
      const data = req.body;
      const result = await this.service.update(id, data);
      res.json(result);
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }

  async delete(req, res) {
    try {
      const id = req.params.id;
      await this.service.delete(id);
      res.json({ message: 'Deleted successfully' });
    } catch (err) {
      res.status(500).json({ error: err.message });
    }
  }
}

3. Middleware xử lý lỗi chung

Tạo middleware errorHandler để xử lý lỗi một cách thống nhất và tái sử dụng trong toàn bộ ứng dụng:

// middleware/errorHandler.js
function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).json({ error: err.message });
}

module.exports = errorHandler;

4. Middleware kiểm tra sự tồn tại của User

Tạo middleware checkUserExists để kiểm tra sự tồn tại của user và tránh lặp lại mã kiểm tra này trong các controller:

// middleware/checkUserExists.js
const User = require('../models/User');

async function checkUserExists(req, res, next) {
  const userId = req.params.id;

  try {
    const user = await User.findById(userId);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    req.user = user;
    next();
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: 'Server error' });
  }
}

module.exports = checkUserExists;

5. Đăng ký Middleware trong Routes

Sử dụng middleware trong các routes để kiểm tra sự tồn tại của user và xử lý lỗi chung:

// routes/user/userRoutes.js
const express = require('express');
const UserController = require('../../controllers/UserController');
const checkUserExists = require('../../middleware/checkUserExists');
const errorHandler = require('../../middleware/errorHandler');

const controller = new UserController();
const userRoutes = express.Router();

userRoutes.get('/:id', checkUserExists, (req, res) => controller.getUser(req, res));
userRoutes.put('/:id', checkUserExists, (req, res) => controller.updateUser(req, res));
userRoutes.delete('/:id', checkUserExists, (req, res) => controller.deleteUser(req, res));

// Sử dụng middleware xử lý lỗi chung
userRoutes.use(errorHandler);

module.exports = userRoutes;

6. Kết nối Middleware vào ứng dụng Express

Kết nối middleware vào ứng dụng Express để đảm bảo các lỗi được xử lý thống nhất:

// app.js hoặc server.js
const express = require('express');
const errorHandler = require('./middleware/errorHandler');
const userRoutes = require('./routes/user/userRoutes');
// Import các routes và middleware khác cần thiết

const app = express();

app.use(express.json());

// Đăng ký các routes
app.use('/api/users', userRoutes);
// Đăng ký các routes khác tương tự

// Sử dụng middleware xử lý lỗi chung
app.use(errorHandler);

// Khởi động server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Tóm tắt các phương pháp xử lý:

  1. Cấu trúc thư mục rõ ràng: Phân chia các thành phần của ứng dụng theo mô hình MVC.
  2. Lớp trừu tượng: Tạo AbstractServiceAbstractController để định nghĩa các phương thức CRUD cơ bản và giảm sự lặp lại của mã.
  3. Middleware xử lý lỗi: Tạo middleware errorHandler để xử lý lỗi chung trong toàn bộ ứng dụng.
  4. Middleware kiểm tra sự tồn tại của User: Tạo middleware checkUserExists để kiểm tra sự tồn tại của user và tránh lặp lại mã kiểm tra trong các controller.
  5. Đăng ký Middleware trong Routes: Sử dụng middleware trong các routes để đảm bảo các lỗi và kiểm tra được xử lý một cách hiệu quả.
  6. Kết nối Middleware vào ứng dụng Express: Đảm bảo các middleware được kết nối vào ứng dụng Express để xử lý lỗi và kiểm tra một cách thống nhất.

Qua đó, ứng dụng của bạn trở nên gọn gàng hơn, dễ bảo trì hơn và có khả năng mở rộng tốt hơn.

#Mtips5s #Contact

Fanpage: https://www.facebook.com/mtipscoder

Group trao đổi, chia sẻ: https://www.facebook.com/groups/mtipscoder

Website: https://mtips5s.com

Youtube: https://mtips5s.com

Twitter(X): @takagiks99

Instagram: @khuongkara

Threads: @khuongkara

Google Maps: @khuongkara

#Base Code #Souce Code

Bộ công cụ My Self: @tools.mtips5s.com

Github: @github

Npm: @npm

Docker: @docker

Chúc các bạn thành công!


Written by admin


Comments

This post currently has no responses.

Leave a Reply