Node.js: مشروع RESTful API
آخر تحديث: 2026-08-26
1. خلفية المشروع
كُلفت أليس وبوب بمهمة تتمثل في تطوير واجهة برمجة تطبيقات (API) لإدارة الكتب لصالح مكتبة إلكترونية. كانت أليس مسؤولة عن تصميم بنية التوجيه والبرمجيات الوسيطة، بينما كان بوب مسؤولاً عن كتابة المنطق التجاري. اتفق الاثنان على تنسيق موحد للاستجابات وقواعد معيارية لمعالجة الأخطاء، وفي غضون ساعتين، أكملوا المشروع بأكمله — بدءًا من إعداد المشروع وصولاً إلى تنفيذ وظائف CRUD الكاملة.
(1) ستتعلم
- إنشاء واجهة برمجة تطبيقات (API) كاملة من خلال الجمع بين Express والتوجيه والبرمجيات الوسيطة
- تصميم بنية مجلدات المشروع (المسارات / وحدات التحكم / البرمجيات الوسيطة / النماذج)
- تخزين البيانات في الذاكرة وتنفيذ عمليات CRUD الكاملة
- التحقق من صحة الطلبات والمعالجة الموحدة للأخطاء
- طرق اختبار واجهة برمجة التطبيقات (curl / Postman)
- تصميم نموذج موحد للاستجابة
2. تصميم بنية دليل المشروع
يُعد التسلسل الهرمي المنظم جيدًا للمجلدات أساس قابلية صيانة المشروع. ووفقًا لأفضل الممارسات المتبعة في المجتمع، تنظم أليس المشروع إلى طبقات بناءً على المسؤوليات:
book-api/
├── app.js
├── routes/
│ └── books.js
├── controllers/
│ └── bookController.js
├── middleware/
│ ├── validate.js
│ └── errorHandler.js
└── models/
└── bookModel.js
| الدليل/الملف | المسؤوليات | الوصف |
|---|---|---|
app.js |
ملف الإدخال | إنشاء مثيل لـ Express، وربط المسارات والبرامج الوسيطة |
routes/ |
تعريف المسار | يحدد طرق HTTP والمسارات التي تشير إلى وحدة التحكم المقابلة |
controllers/ |
منطق الأعمال | معالجة الطلب، واستدعاء النموذج، وإرجاع استجابة |
middleware/ |
البرمجيات الوسيطة | القضايا الشاملة مثل التحقق من صحة الطلبات ومعالجة الأخطاء |
models/ |
نماذج البيانات | تخزين البيانات وتغليف عمليات البيانات |
3. تصميم نقاط نهاية واجهة برمجة التطبيقات (API)
بناءً على متطلبات العمل، قام بوب بتجميع قائمة بجميع نقاط نهاية واجهة برمجة التطبيقات (API):
| طريقة HTTP | المسار | الوظيفة | رمز حالة النجاح | رمز حالة الفشل |
|---|---|---|---|---|
| الحصول على | /api/books |
الحصول على جميع الكتب | 200 | — |
| GET | /api/books/:id |
استرداد كتاب واحد | 200 | 404 |
| منشور | /api/books |
كتب جديدة | 201 | 400 |
| PUT | /api/books/:id |
تحديث الكتاب | 200 | 404 / 400 |
| DELETE | /api/books/:id |
Delete Book | 200 | 404 |
4. نموذج الرد الموحد
تصر أليس على اتباع نمط موحد للردود حتى لا يضطر فريق الواجهة الأمامية إلى تخمين أسماء الحقول:
▶ مثال: رد ناجح
{
"success": true,
"data": { "id": 1, "title": "Node.js Guide", "author": "Alice" }
}
▶ مثال: استجابة الخطأ
{
"success": false,
"error": { "code": 404, "message": "Book not found" }
}
| الحقل | النوع | الوصف |
|---|---|---|
success |
منطقية | ما إذا كان الطلب قد نجح أم لا |
data |
أي | البيانات التي يتم إرجاعها في حالة النجاح |
error.code |
الرقم | رمز حالة الخطأ |
error.message |
سلسلة | وصف الخطأ |
5. طبقة نموذج البيانات
يستخدم بوب المصفوفات الموجودة في الدليل models لمحاكاة قاعدة بيانات وتغليف جميع عمليات البيانات:
▶ مثال: bookModel.js
const books = [
{ id: 1, title: "Node.js Guide", author: "Alice", year: 2024 }
];
let nextId = 2;
function findAll() {
return books;
}
function findById(id) {
return books.find(b => b.id === id);
}
function create(data) {
const book = { id: nextId++, ...data };
books.push(book);
return book;
}
function update(id, data) {
const index = books.findIndex(b => b.id === id);
if (index === -1) return null;
books[index] = { ...books[index], ...data };
return books[index];
}
function remove(id) {
const index = books.findIndex(b => b.id === id);
if (index === -1) return false;
books.splice(index, 1);
return true;
}
module.exports = { findAll, findById, create, update, remove };
6. البرمجيات الوسيطة للتحقق من صحة الطلبات
تقوم «أليس» بتنفيذ عملية التحقق من صحة البيانات في طبقة البرمجيات الوسيطة لضمان عدم وصول الطلبات غير الصحيحة إلى وحدة التحكم:
▶ مثال: validate.js
function validateBook(req, res, next) {
const { title, author, year } = req.body;
const errors = [];
if (!title || typeof title !== "string") {
errors.push("title is required and must be a string");
}
if (!author || typeof author !== "string") {
errors.push("author is required and must be a string");
}
if (year !== undefined && (typeof year !== "number" || year < 0)) {
errors.push("year must be a non-negative number");
}
if (errors.length > 0) {
return res.status(400).json({
success: false,
error: { code: 400, message: errors.join("; ") }
});
}
next();
}
module.exports = { validateBook };
7. البرمجيات الوسيطة لمعالجة الأخطاء
▶ مثال: errorHandler.js
function errorHandler(err, req, res, next) {
console.error(err.stack);
const status = err.status || 500;
res.status(status).json({
success: false,
error: { code: status, message: err.message || "Internal Server Error" }
});
}
function createError(status, message) {
const err = new Error(message);
err.status = status;
return err;
}
module.exports = { errorHandler, createError };
8. طبقة وحدة التحكم
يتولى «بوب» معالجة منطق العمل في وحدة التحكم، ويستدعي النموذج، ويعرض استجابة بتنسيق موحد:
▶ مثال: bookController.js
const Book = require("../models/bookModel");
const { createError } = require("../middleware/errorHandler");
function getAllBooks(req, res) {
res.json({ success: true, data: Book.findAll() });
}
function getBookById(req, res, next) {
const book = Book.findById(Number(req.params.id));
if (!book) return next(createError(404, "Book not found"));
res.json({ success: true, data: book });
}
function createBook(req, res) {
const book = Book.create(req.body);
res.status(201).json({ success: true, data: book });
}
function updateBook(req, res, next) {
const book = Book.update(Number(req.params.id), req.body);
if (!book) return next(createError(404, "Book not found"));
res.json({ success: true, data: book });
}
function deleteBook(req, res, next) {
const removed = Book.remove(Number(req.params.id));
if (!removed) return next(createError(404, "Book not found"));
res.json({ success: true, data: { message: "Book deleted" } });
}
module.exports = { getAllBooks, getBookById, createBook, updateBook, deleteBook };
9. تعريفات المسارات
تفصل «أليس» عملية التوجيه عن وحدة التحكم؛ حيث تقتصر مسؤولية عملية التوجيه على التعيين فقط:
▶ مثال: routes/books.js
const express = require("express");
const router = express.Router();
const controller = require("../controllers/bookController");
const { validateBook } = require("../middleware/validate");
router.get("/", controller.getAllBooks);
router.get("/:id", controller.getBookById);
router.post("/", validateBook, controller.createBook);
router.put("/:id", validateBook, controller.updateBook);
router.delete("/:id", controller.deleteBook);
module.exports = router;
10. ملف app.js
▶ مثال: app.js
const express = require("express");
const booksRoute = require("./routes/books");
const { errorHandler } = require("./middleware/errorHandler");
const app = express();
app.use(express.json());
app.use("/api/books", booksRoute);
app.use(errorHandler);
const PORT = 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
11. نظرة عامة على بنية المشروع
رسمت أليس مخططًا هندسيًّا يوضح بوضوح مسار الطلبات:
graph TD
A[app.js Entrance] --> B[routes/books.js]
B --> C{Needs verification?}
C -->|POST/PUT| D[middleware/validate.js]
C -->|GET/DELETE| E[controllers/bookController.js]
D --> E
E --> F[models/bookModel.js]
F --> E
E --> G[Standardized Response Format]
G --> H[Client]
E -->|Exception| I[middleware/errorHandler.js]
I --> H
12. اختبار واجهة برمجة التطبيقات (API)
يستخدم بوب curl للتحقق من كل نقطة نهاية على حدة:
| أمر curl | الوصف |
|---|---|
curl localhost:3000/api/books |
الحصول على جميع الكتب |
curl localhost:3000/api/books/1 |
الحصول على كتاب معين |
curl -X POST -H "Content-Type: application/json" -d '{"title":"New Book","author":"Bob","year":2025}' localhost:3000/api/books |
كتب جديدة |
curl -X PUT -H "Content-Type: application/json" -d '{"year":2026}' localhost:3000/api/books/1 |
تحديث الكتب |
curl -X DELETE localhost:3000/api/books/1 |
حذف الكتاب |
▶ مثال: اختبار عمليات الإدراج والاستعلام
# Add a book
curl -X POST -H "Content-Type: application/json" \
-d '{"title":"Express in Action","author":"Evan","year":2024}' \
localhost:3000/api/books
{"success":true,"data":{"id":2,"タイトル":"Express in Action","author":"Evan","year":2024}}
# Search All Books
curl localhost:3000/api/books
{"success":true,"data":[{"id":1,"title":"Node.js Guide","author":"Alice","year":2024},{"id":2,"title":"Express in Action","author":"Evan","year":2024}]}
13. مثال شامل: واجهة برمجة تطبيقات (API) كاملة لإدارة الكتب
بالجمع بين جميع الوحدات السابقة، إليكم مسار الكود الأساسي للمشروع الكامل:
// models/bookModel.js
const books = [{ id: 1, title: "Node.js Guide", author: "Alice", year: 2024 }];
let nextId = 2;
function findAll() { return books; }
function findById(id) { return books.find(b => b.id === id); }
function create(data) {
const book = { id: nextId++, ...data };
books.push(book);
return book;
}
function update(id, data) {
const index = books.findIndex(b => b.id === id);
if (index === -1) return null;
books[index] = { ...books[index], ...data };
return books[index];
}
function remove(id) {
const index = books.findIndex(b => b.id === id);
if (index === -1) return false;
books.splice(index, 1);
return true;
}
module.exports = { findAll, findById, create, update, remove };
// middleware/validate.js
function validateBook(req, res, next) {
const { title, author } = req.body;
const errors = [];
if (!title || typeof title !== "string") errors.push("title is required");
if (!author || typeof author !== "string") errors.push("author is required");
if (errors.length > 0) {
return res.status(400).json({
success: false,
error: { code: 400, message: errors.join("; ") }
});
}
next();
}
module.exports = { validateBook };
// middleware/errorHandler.js
function errorHandler(err, req, res, next) {
const status = err.status || 500;
res.status(status).json({
success: false,
error: { code: status, message: err.message || "Internal Server Error" }
});
}
function createError(status, message) {
const err = new Error(message);
err.status = status;
return err;
}
module.exports = { errorHandler, createError };
// controllers/bookController.js
const Book = require("../models/bookModel");
const { createError } = require("../middleware/errorHandler");
function getAllBooks(req, res) {
res.json({ success: true, data: Book.findAll() });
}
function getBookById(req, res, next) {
const book = Book.findById(Number(req.params.id));
if (!book) return next(createError(404, "Book not found"));
res.json({ success: true, data: book });
}
function createBook(req, res) {
const book = Book.create(req.body);
res.status(201).json({ success: true, data: book });
}
function updateBook(req, res, next) {
const book = Book.update(Number(req.params.id), req.body);
if (!book) return next(createError(404, "Book not found"));
res.json({ success: true, data: book });
}
function deleteBook(req, res, next) {
const removed = Book.remove(Number(req.params.id));
if (!removed) return next(createError(404, "Book not found"));
res.json({ success: true, data: { message: "Book deleted" } });
}
module.exports = { getAllBooks, getBookById, createBook, updateBook, deleteBook };
// routes/books.js
const express = require("express");
const router = express.Router();
const ctrl = require("../controllers/bookController");
const { validateBook } = require("../middleware/validate");
router.get("/", ctrl.getAllBooks);
router.get("/:id", ctrl.getBookById);
router.post("/", validateBook, ctrl.createBook);
router.put("/:id", validateBook, ctrl.updateBook);
router.delete("/:id", ctrl.deleteBook);
module.exports = router;
// app.js
const express = require("express");
const booksRoute = require("./routes/books");
const { errorHandler } = require("./middleware/errorHandler");
const app = express();
app.use(express.json());
app.use("/api/books", booksRoute);
app.use(errorHandler);
app.listen(3000, () => console.log("Server running on port 3000"));
# Start and Test
node app.js
curl -X POST -H "Content-Type: application/json" \
-d '{"title":"Clean Code","author":"Robert","year":2008}' \
localhost:3000/api/books
curl localhost:3000/api/books/1
curl -X DELETE localhost:3000/api/books/1
❓ أسئلة شائعة
curl في سطر الأوامر، أو Postman، أو المكون الإضافي Thunder Client لـ VS Code للحصول على واجهة رسومية، ومكتبة supertest للاختبار الآلي.{ success: false, error: { code: 404, message: "Book not found" } }.📖 ملخص
- المفاهيم الأساسية لخلفية المشروع وكيفية استخدامها
- المفاهيم الأساسية وتطبيقات تصميم بنية دليل المشروع
- المفاهيم الأساسية وتطبيقات تصميم نقاط نهاية واجهة برمجة التطبيقات (API)
- المفاهيم الأساسية لاستخدام «تنسيق الاستجابة الموحد»
- المفاهيم الأساسية لطريقة استخدام طبقة نموذج البيانات
- المفاهيم الأساسية واستخدامات برامج الوسيطة الخاصة بالتحقق من صحة الطلبات
- المفاهيم الأساسية واستخدامات البرمجيات الوسيطة لمعالجة الأخطاء
- المفاهيم الأساسية لطبقة وحدة التحكم وكيفية استخدامها
📝 تمارين
- أكمل جميع أمثلة الأكواد الواردة في هذا الدرس وتأكد من أن كل منها يعمل بشكل صحيح.
- قم بتعديل المثال الشامل وأضف الإضافات الخاصة بك
- راجع الوثائق الرسمية، وحدد واجهة برمجة تطبيقات (API) واحدة أو اثنتين لم يتم تناولهما في هذا الدرس، واكتب كود اختبار لهما.
- التأمل: كيف ستطبق ما تعلمته في هذا الدرس على مشروع في الواقع العملي؟
- حاول أن تجمع بين ما تعلمته في هذا الدرس والمواد التي درستها في الدروس السابقة لإنشاء مشروع صغير.