المقدمة
عند تصميم واجهات برمجة التطبيقات (APIs)، يُعد مفهوم الـ Idempotency من المفاهيم المُهمة لضمان استقرار الأنظمة و سلامة بياناتها، لا سيما في الأنظمة الموزعة حيث ترتفع احتمالية تكرار الطلبات نتيجة لمشاكل الشبكة Network Failures أو إعادة المحاولة التلقائية Retries.
في هذا المقال سنستكشف مفهوم الـ idempotency، أهميته في تصميم الـ APIs، الآليات المتبعة لتحقيقه و متى يُستخدم.
ما هو الـ Idempotency؟
الـ Idempotency هو مفهوم مُستعار من الرياضيات، و يعني أن تنفيذ عملية مُعينة مرة واحدة أو عدة مرات سيُعطي نفس النتيجة. في سياق الـ APIs هذا يعني أنه يُمكن تنفيذ نفس الطلب Request عدة مرات دون أن يُؤثر ذلك على حالة النظام أو ينتج عنه آثار جانبية غير مرغوب فيها.
// idempotent operation
const result = Math.abs(-5); // النتيجة: 5
const result2 = Math.abs(-5); // النتيجة: 5 (نفس النتيجة)
// non-idempotent operation
let counter = 0;
const increment = () => ++counter;
increment(); // النتيجة: 1
increment(); // النتيجة: 2 (نتيجة مختلفة)
أهمية الـ Idempotency في الـ APIs
- أحيانا يفقد العميل تأكيد نجاح العملية بسبب مشاكل الشبكة فيُعيد إرسال الطلب. لذلك يجب أن يتحمل النظام تكرار نفس الطلب دون تكرار التنفيذ.
- بعض الأنظمة تعتمد على إعادة المحاولة تلقائيا عند فشل الطلب مؤقتا مما يجعل دعم الـ idempotency ضروريا لتفادي تكرار غير مرغوب فيه.
- في العمليات الحساسة كتنفيذ المعاملات المالية قد يؤدي تكرار التنفيذ إلى أخطاء خطيرة إن لم يُراعى مفهوم الـ idempotency.
- في الأنظمة الموزعة تكرار الطلبات أمر شائع بسبب الأعطال الجزئية، لذلك يُدعم الـ idempotency موثوقية النظام و سلامة بياناته.
فرصة توظيف مميزة Hybrid بمرتب يوصل لـ 35,000 جنيه 🚀
لو بتدور على شغل حقيقي يطور ويقيّم مهاراتك بدل الـ CV، يبقى لازم تشارك في الـ Hiring Quest الجديدة من CodeXQuests 👇
💼 Backend Developer (Mid-Level) @ 4Sale – Hybrid
4Sale هي واحدة من أقوى منصات البيع والشراء في الكويت وعايزين يضموا لمهندسيهم شخص شاطر في:
🔸 Laravel, Go
🔸 MySQL , PostgreSQL
🔸 Docker, REST APIs, CI/CD
المميز في الـ Hiring Quest:
✅ مفيش مقابلات مملة
✅ مفيش تصفية للـ CVs
✅ الفرصة بتتحدد على حسب شغلك الفعلي
✅ أفضل المشاركين هيتراجع شغلهم وفرصة التوظيف حقيقية 100%
📅 سجل مجانًا قبل ما التسجيل يقفل خلال يومين!
ابدأ المشوار، وورّيهم شغلك وفي نفس الوقت ابني CV عملي من مشاريع حقيقة! 💪

الـ Idempotency و الـ HTTP Methods
في سياق بروتوكول HTTP، العملية تكون Idempotent عندما يُمكن تكرارها عدة مرات دون أن يتغير الناتج النهائي على حالة النظام. أي أن تنفيذ العملية مرة واحدة أو مئة مرة يعطي نفس التأثير من حيث حالة المورد.
عند الالتزام بمبادئ REST في تصميم الـ APIs، نجد أن بعض الأساليب (HTTP Methods) بطبيعتها تدعم الـ Idempotency، في حين أن البعض الآخر لا.
الـ Methods يُفترض أن تكون Idempotent
GET /api/users/123 # قراءة بيانات المستخدم
PUT /api/users/123 # تحديث كامل للمستخدم
DELETE /api/users/123 # حذف المستخدم
HEAD /api/users/123 # الحصول على metadata فقط
OPTIONS /api/users # معرفة الخيارات المتاحة
TRACE /api/users # تتبع المسار (نادر الاستخدام)
الـ Methods غير Idempotent بطبيعتها
POST /api/users # إنشاء مستخدم جديد
PATCH /api/users/123 # تحديث جزئي للمستخدم
لماذا POST ليست Idempotent؟
// كل مرة نستدعي فيها هذا الطلب
POST /api/orders
{
"productId": "laptop-123",
"quantity": 1,
"price": 999
}
// ينتج عنه طلب جديد بـ ID مختلف
// الطلب الأول: order-001
// الطلب الثاني: order-002
// الطلب الثالث: order-003
المشكلة واضحة هنا: كل استدعاء يُنشئ طلب جديد! هذا بالضبط ما نريد تجنبه.
لماذا PATCH قد يكون غير Idempotent؟
// مثال على PATCH غير idempotent
PATCH /api/users/123
{
"operation": "increment",
"field": "loginCount",
"value": 1
}
// أول استدعاء: loginCount = 5 → 6
// ثاني استدعاء: loginCount = 6 → 7
// ثالث استدعاء: loginCount = 7 → 8
كل مرة نستدعي فيها الطلب، يزيد العداد! هذا سلوك غير idempotent. لكن يُمكن للأسلوب PATCH أن يكون idempotent إذا صُمم بالشكل الصحيح:
// مثال على PATCH idempotent
PATCH /api/users/123
{
"email": "user@example.com",
"phone": "+1234567890"
}
// كل الاستدعاءات تضع نفس القيم
// النتيجة دائماً نفسها بغض النظر عن عدد مرات التنفيذ
لماذا PUT تُعتبر Idempotent؟
// نفس الطلب عدة مرات
PUT /api/users/123
{
"name": "أحمد محمد",
"email": "ahmed@example.com",
"age": 30
}
// أول مرة: يُنشئ أو يُحدث المستخدم
// المرات التالية: نفس البيانات تُكتب مرةأخرى
// والنتيجة النهائية واحدة
حالة خاصة مع الأسلوب DELETE
// هذا idempotent
DELETE /api/users/123
// أول مرة: يحذف المستخدم (200 أو 204)
// المرات التالية: لا يوجد شيء للحذف (404)
// لكن حالة النظام لم تتغير بعد أول حذف
لكن انتبه لهذه الحالة:
// هذا ليس idempotent!
DELETE /api/users/last-login
// أول مرة: يُحذف المستخدم الذي دخل آخر مرة
// ثاني مرة: يُحذف مستخدم آخر!
// كل مرة يُحذف مستخدم مختلف
طُرق تطبيق الـ Idempotency
هناك عدة طُرق لتطبيق الـ Idempotency في الـ APIs، كل واحدة منها مُناسبة لسيناريوهات مختلفة:
معرفات الطلب الفريدة (Idempotency Key)
الطريقة الأكثر شيوعا هي إرفاق مُعرّف فريد (idempotency key) مع كل طلب. إذا تلقّى الخادم طلباً بنفس المُعرّف مرة أخرى، يتعرّف عليه كطلب مُكرر و يتجاهله.
// العميل يُرسل مفتاح فريد
const response = await fetch('/api/payments', {
method: 'POST',
headers: {
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ amount: 100, userId: '123' })
});
// الخادم يتحقق من المفتاح
app.post('/api/payments', async (req, res) => {
const key = req.headers['idempotency-key'];
const existing = await Payment.findOne({ idempotencyKey: key });
if (existing) {
return res.json(existing); // إرجاع النتيجة السابقة
}
// معالجة الطلب الجديد...
});
التعديلات على قاعدة البيانات (عمليات Upsert)
لمنع التكرار في قاعدة البيانات، نستخدم عمليات "upsert" (تحديث أو إدراج). هذا يضمن بقاء قاعدة البيانات متسقة دون إنشاء موارد مُكررة.
-- استخدام INSERT ... ON CONFLICT في PostgreSQL
INSERT INTO user_profiles (user_id, name, email)
VALUES ('123', 'أحمد محمد', 'ahmed@example.com')
ON CONFLICT (user_id)
DO UPDATE SET
name = EXCLUDED.name,
email = EXCLUDED.email;
// في Node.js مع Prisma
const user = await prisma.user.upsert({
where: { id: userId },
update: { name, email },
create: { id: userId, name, email }
});
متى تستخدم الـ Idempotency؟
ليس كل API يحتاج للـ Idempotency. إليك الحالات التي من الجيد تطبيقه فيها:
- العمليات المالية (المدفوعات، التحويلات …)
- إنشاء الطلبات أو الحجوزات
- إرسال الإشعارات المهمة
- العمليات التي لها تكلفة (مثل إرسال SMS)
- أي عملية يمكن أن تسبب مشاكل إذا تكررت
في الختام
الـ Idempotency ليس مجرد تحسين إضافي في تصميم الـ APIs، بل يُعد عنصر جوهري في بناء أنظمة أكثر استقرارا و موثوقية. من خلال فهم متى و أين نطبقه و اختيار الاستراتيجية المناسبة لتنفيذه نستطيع تقليل الأخطاء، حماية البيانات و تحسين تجربة المستخدم. في النهاية، الهدف من دعم الـ Idempotency هو ضمان أن يتصرف النظام بشكل متوقع حتى في الظروف غير المتوقعة.
Discussion