بناء واجهة برمجة تطبيقات (API) لاكتشاف الفيديوهات باستخدام GraphQL
عندما نمت قاعدة بيانات الفيديوهات لدينا لتصل إلى مئات الآلاف من السجلات، أصبحت واجهة برمجة التطبيقات (API) الخاصة بنا هي عنق الزجاجة.
كانت الشاشة الواحدة تتطلب خمس عمليات استدعاء REST مختلفة لعرض الفيديوهات الرائجة، وتفاصيل القناة، والوسوم، وعدد المشاهدات، والتوصيات. وكان على مستخدمي الهواتف المحمولة عبر الاتصالات البطيئة إرسال 30 طلبًا لمجرد تحميل صفحة واحدة.
يحل GraphQL هذه المشكلة؛ حيث يطلب العميل ما يحتاجه بالضبط في طلب واحد.
لقد قمت ببناء واجهة برمجة تطبيقات لاكتشاف الفيديوهات للإنتاج باستخدام Strawberry وFastAPI. إليكم كيف فعلت ذلك.
لماذا Strawberry؟
لقد اختبرت Graphene وAriadne، ولكن Strawberry فاز لهذه الأسباب:
• تلميحات النوع (Type hints) هي المخطط (schema). تكتب كود Python، ويقوم Strawberry ببناء أنواع GraphQL. لا حاجة للمزامنة اليدوية. • هو يدعم البرمجة غير المتزامنة (async-native) بشكل أصلي. وهذا يسمح للـ API بالتعامل مع العديد من الطلبات دون حظر حلقة الأحداث (event loop). • التكامل مع FastAPI سلس للغاية. حيث توجد نقطة نهاية GraphQL بجوار مسارات REST الحالية مباشرة. • يتضمن DataLoader مدمجًا. هذه الأداة تحل مشكلة N+1 مباشرة.
مجموعة البيانات (The Data Stack)
البيانات موجودة في قاعدة بيانات SQLite تدار بواسطة موقع PHP. أستخدم SQLite FTS5 للبحث السريع عن النصوص الكاملة.
تقرأ خدمة Python هذه القاعدة كطبقة للقراءة فقط، مما يضمن وجود مصدر واحد للحقيقة.
لجعل تجربة البحث جيدة، قمت بدمج درجات صلة FTS5 مع إشارة الشعبية. وهذا يمنع فيديو واحد واسع الانتشار من طغيان نتائج البحث الأخرى.
حل مشكلة N+1
أحد الفخاخ الشائعة في GraphQL هو مشكلة N+1. إذا قمت بجلب 20 فيديو ثم جلب القناة لكل فيديو منها، فستقوم واجهة برمجة التطبيقات البسيطة بتشغيل 21 استعلامًا لقاعدة البيانات.
يقوم DataLoader بإصلاح ذلك عن طريق التجميع (batching). حيث يجمع جميع معرفات القنوات (channel IDs) في نبضة واحدة ويشغل استعلامًا واحدًا لجلبها جميعًا. وقد أدى ذلك إلى خفض وقت الاستعلام لدينا من 40 مللي ثانية إلى أقل من 5 مللي ثانية.
خيارات التصميم الرئيسية
• معرفات غامضة (Opaque IDs): أستخدم السلاسل النصية (strings) للمعرفات. وهذا يسمح بإجراء تغييرات مستقبلية دون كسر تطبيقات العملاء. • قابلية العدم المتعمدة (Intentional Nullability): أحدد الحقول التي يمكن أن تكون فارغة. وهذا يساعد العملاء على التعامل مع البيانات المفقودة دون حدوث انهيار. • مخطط للقراءة فقط (Read-only Schema): لا تتعامل واجهة برمجة تطبيقات GraphQL مع عمليات الكتابة، مما يزيل الكثير من الصداع الأمني. • التخزين المؤقت عند الحافة (Edge Caching): يستخدم GraphQL طريقة POST افتراضيًا، وهو أمر يصعب تخزينه مؤقتًا. لذا أستخدم الاستعلامات المستمرة التلقائية (APQ) للسماح بالتخزين المؤقت عبر Cloudflare.
إذا كنت تعاني من كثرة نقاط النهاية المخصصة أو معاملات الاستعلام المعقدة، فإن هذه المجموعة تعد خيارًا قويًا.
