يدفع العميل، يرسل Stripe حدث payment_intent.succeeded إلى الواجهة الخلفية الخاصة بك، ومن المفترض أن تقوم نقطة النهاية الخاصة بك بوضع علامة "مدفوع" على الطلب. هذه الخطوة الأخيرة هي التي تفشل بصمت. يصل الويب هوك (webhook)، يرمي المعالج الخاص بك خطأً، ولا يلاحظ أحد ذلك حتى تصل تذكرة دعم تقول "لقد دفعت ولكن حسابي لا يزال يظهر على أنه غير مدفوع." أنت بحاجة إلى اختبار في التكامل المستمر (CI) يثبت أن الحدث قد وصل وتمت معالجته بشكل صحيح، في كل مرة تقوم فيها بالنشر.
الجزء الصعب هو أن الويب هوك (webhook) هو مكالمة HTTP واردة من Stripe إليك، وليس طلبًا تقوم به أنت. معظم أدوات اختبار واجهة برمجة التطبيقات (API) مصممة لإرسال طلب والتحقق من الاستجابة، وهو الشكل المعاكس. لذا يصبح السؤال: كيف يمكنك التحقق من شيء يصل وفقًا لجدوله الزمني الخاص به، داخل تشغيل التكامل المستمر (CI)، دون مراقبة بشرية؟ يوضح هذا الدليل الطريقة الصادقة والمدعومة للقيام بذلك باستخدام Apidog، ويبدأ بحد قيود يجب أن تعرفه مقدمًا. إذا كنت تريد الصورة الأوسع لاختبار نقاط النهاية التي تعتمد على الأحداث أولاً، فإن دليلنا حول كيفية اختبار الويب هوكس يمهد الطريق، وتغطي وثائق الويب هوكس الخاصة بـ Stripe نموذج تسليم الأحداث.
القيود التي يجب أن تأخذها في الاعتبار عند التصميم
إليك الحقيقة الجوهرية، المذكورة بوضوح في وثائق Apidog الخاصة: “ApiDog لا يدعم بشكل أساسي الاستماع للويب هوكس.” لا يتواجد Apidog على عنوان URL عام ويلتقط مكالمات Stripe الواردة في الوقت الفعلي. إذا كنت تأمل في توجيه Stripe إلى مستمع Apidog ومشاهدة الأحداث وهي تصل، فإن هذا المسار غير موجود.
قد يبدو هذا طريقًا مسدودًا. لكنه ليس كذلك. إنه يغير فقط شكل الاختبار. بدلاً من اعتراض الويب هوك عند وصوله، يمكنك التقاطه في الواجهة الخلفية الخاصة بك، وتخزينه، ثم جعل Apidog يستعلم عن ذلك السجل المخزن ويتحقق منه. الالتقاط أولاً، ثم التحقق ثانيًا. بمجرد قبول هذا الفصل، يصبح سير العمل بأكمله مباشرًا، والأهم من ذلك أنه يتناسب تمامًا مع التكامل المستمر (CI) لأن استعلام قاعدة البيانات محدد وقابل للتكرار.
كيف يبدو نمط الالتقاط ثم الاستعلام
النمط الذي توصي به وثائق Apidog يتكون من أربعة أجزاء متحركة:
- أنشئ نقطة نهاية في خدمة الواجهة الخلفية الخاصة بك لالتقاط الويب هوكس الواردة من Stripe.
- اخزن بيانات حدث الويب هوك في جدول
Stripe event logsفي قاعدة البيانات الخاصة بك. - استخدم معالج ما بعد الطلب (Post-Request Processor) في Apidog للاستعلام عن قاعدة البيانات الخاصة بك.
- استرجع حدث الويب هوك المخزن وتحقق منه مقابل النتائج المتوقعة.
اثنتان من هذه الخطوات موجودتان في التعليمات البرمجية الخاصة بك، واثنتان في Apidog. نقطة نهاية الالتقاط وجدول التسجيل هي مسؤوليتك للبناء، لأنها تعمل داخل تطبيقك الخاص. تبدأ مهمة Apidog بمجرد دخول الحدث إلى قاعدة البيانات الخاصة بك: فهو يتصل بقاعدة البيانات هذه ويقرأ السجل مرة أخرى لتأكيد معالجة الحدث بالطريقة التي تتوقعها. حافظ على هذا التقسيم واضحًا والباقي يقع في مكانه.
الخطوة 1: بناء نقطة نهاية الالتقاط
تحتاج الواجهة الخلفية الخاصة بك إلى مسار يمكن لـ Stripe إرسال طلب POST إليه. هذا هو رمز تطبيق عادي، وليس ميزة Apidog. يبدو معالج Express الأدنى الذي يتحقق من التوقيع ويسجل الحدث كما يلي:
import express from "express";
import Stripe from "stripe";
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
app.post(
"/webhooks/stripe",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
req.headers["stripe-signature"],
endpointSecret
);
} catch (err) {
return res.status(400).send(`Signature check failed: ${err.message}`);
}
// Persist the event so a test can read it back later.
await db.query(
`INSERT INTO stripe_event_logs (event_id, type, payload, handled_at)
VALUES ($1, $2, $3, now())
ON CONFLICT (event_id) DO NOTHING`,
[event.id, event.type, JSON.stringify(event.data.object)]
);
if (event.type === "payment_intent.succeeded") {
const intent = event.data.object;
await markOrderPaid(intent.metadata.order_id);
}
res.json({ received: true });
}
);
أمران مهمان هنا. أولاً، تتحقق من توقيع Stripe باستخدام constructEvent قبل الثقة بأي شيء، وهي خطوة الأمان غير القابلة للتفاوض لأي مستقبل ويب هوك. إذا كنت تريد معرفة المنطق الكامل وراء هذا التحقق، فإن شرحنا حول التحقق من توقيع الويب هوك يتناول سبب كون مقارنة النص الأصلي للجسم هي الطريقة الآمنة الوحيدة للقيام بذلك. ثانيًا، تكتب الحدث إلى جدول Stripe event logs. هذا السجل هو ما سيقرأه Apidog. يحافظ شرط ON CONFLICT DO NOTHING على عدم تكرارية السجل، نظرًا لأن Stripe يمكن أن يسلم نفس الحدث أكثر من مرة.
الخطوة 2: ربط قاعدة بياناتك في بيئة Apidog
يدعم Apidog الاتصال بقاعدة بيانات في البيئة المقابلة، وهذا الاتصال هو ما يجعل هذا النمط بأكمله يعمل. قم بإعداد اتصال قاعدة بيانات للبيئة التي يستهدفها تشغيل التكامل المستمر (CI) الخاص بك، سواء كانت قاعدة بيانات Postgres للمرحلة التجريبية أو قاعدة بيانات اختبار مخصصة. بمجرد إنشاء الاتصال، يمكن لخطوة الاختبار تشغيل SQL ضدها واستعادة سجلات حقيقية.
طابق الاتصال بالبيئة التي تختبرها. يجب أن يستعلم الاختبار الذي يتم تشغيله مقابل بيئة التدريج (staging) عن قاعدة بيانات التدريج، بحيث يكون الحدث الذي يقوم اختبارك بتشغيله هو الحدث الذي يقرأه اختبارك. تعد البيئات غير المتطابقة السبب الأكثر شيوعًا لفشل نقطة نهاية الالتقاط التي تعمل بشكل صحيح في التحقق.
الخطوة 3: إضافة معالج ما بعد الطلب للاستعلام عن السجل
هذا هو جوهر الأمر. Post-Request Processor (معالج ما بعد الطلب) هو ميزة Apidog التي تستعلم عن قاعدة البيانات الخاصة بك وتتحقق من حدث الويب هوك المسجل داخل الاختبار. تقوم بإرفاقه بطلب في سيناريو الاختبار الخاص بك. بعد تشغيل الطلب، ينفذ المعالج استعلام SQL الخاص بك، ويقرأ الحدث المخزن، ويسمح لك بالتحقق من النتيجة.
تدفق واقعي لحالة payment_intent.succeeded:
- يقوم سيناريو الاختبار الخاص بك بتشغيل الدفع. قد يكون ذلك طلبًا ينشئ نية دفع ويؤكدها في وضع اختبار Stripe، أو أداة مساعدة (fixture) تقوم بإطلاق حدث اختبار معروف إلى نقطة نهاية الالتقاط الخاصة بك.
- يقوم Stripe بتسليم الويب هوك إلى مسار
/webhooks/stripeالخاص بك، والذي يتحقق من التوقيع ويكتب سجلًا فيstripe_event_logs. - يقوم
Post-Request Processorفي الخطوة التالية بالاستعلام عن ذلك الجدول بحثًا عن الحدث.
الاستعلام الذي يقوم المعالج بتشغيله هو SQL عادي:
SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE type = 'payment_intent.succeeded'
ORDER BY handled_at DESC
LIMIT 1;
ثم تتحقق من السجل الذي تم إرجاعه. ينجح الاختبار عندما تتطابق البيانات المسجلة مع توقعاتك: أن يكون type هو payment_intent.succeeded، و event_id يطابق الذي قمت بتشغيله، وأن يكون مبلغ payload مساويًا للمبلغ الذي قمت بفرضه، وأن يكون handled_at مملوءًا، مما يثبت أن المعالج الخاص بك قد عمل بالفعل بدلاً من أن يكون السجل مجرد عنصر نائب. استرجع حدث الويب هوك المخزن، وقارنه بالنتيجة المتوقعة، ودع التحقق يقرر النجاح أو الفشل.
نظرًا لأن توقيت تسليم الويب هوك ليس فوريًا، امنح الحدث لحظة للوصول قبل الاستعلام. خطوة تأخير قصيرة، أو حلقة استقصاء تعيد محاولة الاستعلام عدة مرات قبل الفشل، تمنع الاختبار من سباق تسليم Stripe. هذا هو المكان الوحيد الذي تتسرب فيه الطبيعة غير المتزامنة للويب هوكس إلى تصميم الاختبار الخاص بك، ونافذة إعادة محاولة صغيرة تتعامل معها بشكل نظيف.
ملاحظة حول إعادة التوجيه في الوقت الفعلي أثناء التطوير المحلي
تم تصميم نمط الالتقاط ثم الاستعلام (capture-then-query) للتكامل المستمر (CI)، حيث تكون قاعدة البيانات والسجل المخزن هي بالضبط ما تريده. يختلف التطوير المحلي. عندما تكتب المعالج على جهاز الكمبيوتر المحمول الخاص بك، لا يمكن لـ Stripe الوصول إلى localhost مباشرة، لذلك تحتاج إلى شيء لإعادة توجيه الأحداث إلى جهازك في الوقت الفعلي.
لهذا الغرض، تشير وثائق Apidog إلى خدمة ترحيل الويب هوك، وتذكر Stripe CLI و Ngrok كأمثلة. يمكن لواجهة سطر الأوامر (CLI) الخاصة بـ Stripe الاستماع وإعادة توجيه الأحداث مباشرة إلى المنفذ المحلي الخاص بك:
stripe listen --forward-to localhost:3000/webhooks/stripe
هذا يمنحك أحداثًا حية أثناء بناء المعالج. يقوم Ngrok بنفس المهمة عن طريق كشف المنفذ المحلي الخاص بك على عنوان URL عام تسجله كنقطة نهاية لـ Stripe. استخدم هذه الأدوات لدورة التطوير الداخلية، ثم اعتمد على تدفق قاعدة البيانات بالإضافة إلى Post-Request Processor للتحققات التي تعمل في مسار عملك. الاثنان متكاملان: الترحيل (relay) للبناء، والالتقاط ثم الاستعلام (capture-then-query) للإثبات.
لا تخلط هذا بميزة الويب هوك الأصلية في Apidog
يمتلك Apidog بالفعل ميزة تسمى حرفياً Webhook، ومن السهل افتراض أن هذه هي الطريقة التي تلتقط بها أحداث Stripe. هذا ليس صحيحًا، وخلط الأمور سيكلفك وقتًا طويلاً. ميزة Webhook الأصلية مخصصة لتحديد وتوثيق الويب هوك الصادر، مما يعني نقطة نهاية HTTP التي يستدعيها نظامك الخاص عند وقوع حدث. يبدأ النظام المكالمة إلى عنوان URL خارجي، وهو عكس نقطة النهاية العادية حيث يتصل بك العملاء. تُستخدم لوصف إشعارات تغيير الحالة ونتائج المهام غير المتزامنة في وثائق API الخاصة بك، وليس لاستقبال مكالمات Stripe الواردة.
إذا كنت ترغب في توثيق أحد الويب هوكس الصادرة الخاصة بك، فإن التدفق قصير:
- انقر على أيقونة
+في الشريط الجانبي الأيسر. - اختر
New Other Protocol APIs(واجهات برمجة تطبيقات البروتوكولات الأخرى الجديدة)، ثمWebhook. - املأ الحقول المطلوبة:
Request Method(طريقة الطلب، عادةً POST)،Webhook Name(اسم الويب هوك)،Debug URLاختياري (عنوان URL للتصحيح) للاختبار فقط، وOther Info(معلومات أخرى) لجسم الطلب، الرؤوس، والتكوين. - انقر على
Save(حفظ).
لتجربتها، أدخل عنوان URL في حقل Debug URL وانقر على Send لمحاكاة مكالمة الويب هوك. تحذير واحد يستحق التذكر: Debug URL مخصص للاختبار فقط ولن يظهر في وثائقك المنشورة أو تصدير OpenAPI الخاص بك. للحصول على معالجة أشمل لتصميم وتوثيق ردود الاتصال بالأحداث، تتناول مقالتنا حول الويب هوكس في تصميم واجهة برمجة التطبيقات مكانها. النسخة المختصرة لهذه المقالة: ميزة Webhook الأصلية تحدد أحداثك الصادرة، ونمط الالتقاط ثم الاستعلام (capture-then-query) يتحقق من أحداث Stripe الواردة. احتفظ بهما في خانتين ذهنيتين منفصلتين.
الاختلافات والتعزيز
بمجرد أن يعمل التحقق الأساسي، هناك بعض التحسينات التي تجعله جاهزًا للإنتاج. أولاً، تحقق من أكثر من نوع الحدث. تحقق من event_id من البداية إلى النهاية لتعرف أن الحدث المحدد الذي قمت بتشغيله هو نفسه الذي قمت بالتحقق منه، وليس بقايا من تشغيل سابق. قم باقتطاع أو تحديد نطاق جدول stripe_event_logs لكل تشغيل اختبار إذا تراكمت الأحداث.
ثانيًا، اختبر مسارات الفشل. أطلق حدثًا يجب أن يرفضه المعالج الخاص بك، توقيعًا سيئًا أو نوعًا غير متوقع، وتحقق من عدم كتابة طابع زمني handled_at. مجموعة اختبار الويب هوك التي تتحقق فقط من المسار السعيد تفوت الحالات التي توقظك فعليًا في الساعة الثانية صباحًا. تغطي ملاحظاتنا حول أفضل ممارسات الويب هوك للدفع سلوك عدم التكرار وإعادة المحاولة الذي يستحق ترميزه في هذه الاختبارات.
ثالثًا، اجعل التحقق مرتبطًا بالمعنى التجاري، وليس مجرد التسليم. "وصل الحدث" أضعف من "انتقل الطلب إلى حالة مدفوع". إذا كان المعالج الخاص بك يقوم بتحديث جدول orders، أضف استعلامًا ثانيًا يؤكد أن الحالة اللاحقة قد تغيرت، بحيث يثبت الاختبار السلسلة بأكملها وليس مجرد كتابة السجل.
يمكنك أيضًا أخذ هذا إلى ما بعد بوابة الدمج. بمجرد حفظ السيناريو في Apidog، قم بجدولته للتشغيل بشكل دوري بحيث يظهر أي معالج ويب هوك معطل حتى بين عمليات النشر. يوضح دليلنا حول كيفية جدولة اختبارات API في Apidog كيفية وضع هذا التحقق نفسه على مؤقت.
أتمتة سير العمل باستخدام Apidog CLI
يؤتي كل ما سبق ثماره عندما يعمل دون إشراف، وهذا هو المكان الذي يأتي فيه Apidog CLI. هذه قصة تكامل مستمر (CI) بطبيعتها، لذا فإن ربط السيناريو المحفوظ بخط أنابيبك هو النهاية الطبيعية. قم بتثبيت CLI والمصادقة باستخدام رمزك المميز:
npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
ثم قم بتشغيل سيناريو التحقق من الويب هوك المحفوظ الخاص بك بدون واجهة رسومية مقابل البيئة التي تحتوي قاعدة بياناتها على سجلات الأحداث:
apidog run --access-token $APIDOG_ACCESS_TOKEN -t <SCENARIO_ID> -e <ENV_ID> -r cli
هنا -t هو معرف سيناريو الاختبار، و -e هو معرف البيئة، و -r يختار المُبلغ. استخدم -r html,cli إذا كنت تريد تقريرًا قابلاً للتصفح بجانب مخرجات وحدة التحكم لنتائج التكامل المستمر (CI) الخاصة بك. يحمل السيناريو Post-Request Processor واستعلام قاعدة البيانات الخاص به، لذا فإن أمرًا واحدًا يشغل التدفق، ويقرأ سجل stripe_event_logs، ويعيد رمز خروج غير صفري إذا فشل التحقق، وهذا بالضبط ما يحتاجه خط الأنابيب لحظر الدمج. يغطي دليل تثبيت Apidog CLI إعداد الرمز المميز، ويعرض شرح مسار عمل CI/CD الخاص بنا الربط الكامل لـ GitHub Actions حول هذا الأمر.
الأسئلة المتداولة
هل يمكن لـ Apidog استقبال ويب هوك Stripe مباشرة؟ لا. وثائق Apidog تنص بوضوح على أنها "لا تدعم بشكل أساسي الاستماع للويب هوكس." يمكنك التقاط الحدث في نقطة نهاية الواجهة الخلفية الخاصة بك، وتخزينه في قاعدة بيانات، ويقوم Apidog بقراءته مرة أخرى باستخدام Post-Request Processor. لإعادة التوجيه في الوقت الفعلي أثناء التطوير المحلي، استخدم خدمة ترحيل مثل Stripe CLI أو Ngrok بدلاً من ذلك.
أين تحدث التحققات فعليًا؟ داخل خطوة Post-Request Processor على طلب في سيناريو الاختبار الخاص بك. تستعلم عن جدول Stripe event logs الخاص بك عبر اتصال قاعدة البيانات الذي قمت بتكوينه في البيئة، وتسترجع الحدث المخزن، وتقارنه بالقيم المتوقعة. ينجح الاختبار عندما تتطابق البيانات المسجلة.
هل أحتاج إلى خطة مدفوعة لتدفق التحقق من قاعدة البيانات؟ لا تذكر وثائق Apidog لهذا التدفق أي قيود على الخطط، لذلك لن يخترع هذا الدليل واحدة. الإجابة الصادقة هي التحقق من تفاصيل الخطة الحالية على صفحة الأسعار. يمكنك تنزيل Apidog وإعداد مشروع اختبار لترى معالج ما بعد الطلب واتصال قاعدة بيانات البيئة بنفسك.
كيف أتعامل مع التأخير بين التشغيل والتسليم؟ تسليم الويب هوك ليس فوريًا، لذا أضف انتظارًا قصيرًا أو إعادة محاولة استقصاء قبل الاستعلام حتى لا يسبق اختبارك تسليم Stripe. عادةً ما تكون بضع محاولات على مدى بضع ثوانٍ كافية. إذا كنت جديدًا في التحقق من نقاط النهاية غير المتزامنة، فابدأ بدليل كيفية اختبار الويب هوكس العام قبل الخوض في تفاصيل Stripe.
هل ميزة الويب هوك الأصلية مفيدة هنا على الإطلاق؟ ليست لالتقاط أحداث Stripe. تلك الميزة تحدد وتوثق الويب هوكس الصادرة الخاصة بك، حيث يستدعي نظامك عنوان URL خارجيًا. إنها أداة توثيق وتصميم، منفصلة عن نمط الالتقاط ثم الاستعلام (capture-then-query) الوارد الذي تستخدمه هذه المقالة. حافظ على فصل واضح بين الاثنين.
الخلاصة
لا يمكنك توجيه Stripe إلى Apidog والتقاط الأحداث مباشرة، والتظاهر بخلاف ذلك يؤدي إلى فترة ما بعد الظهر محبطة. المسار المدعوم أنظف مما يبدو للوهلة الأولى: التقط الويب هوك في نقطة النهاية الخاصة بك، وسجله في جدول Stripe event logs، ثم دع Post-Request Processor الخاص بـ Apidog يستعلم عن هذا السجل ويؤكد معالجة الحدث. قم بتضمين السيناريو المحفوظ في apidog run وستثبت خطوط أنابيبك، في كل دمج، أن حدث دفع حقيقي ينقل طلبك إلى حالة مدفوع. جربه مجانًا، لا يلزم وجود بطاقة ائتمان، وقم بوضع تأكيد حقيقي خلف الويب هوك الأكثر أهمية.
