طبقة واجهة برمجة التطبيقات الحديثة: GraphQL، وREST، وtRPC
انتهى النقاش. أنت بحاجة إلى نوع الأمان. كيفية تصميم طبقة API قابلة للتطوير لا تكسر الواجهة الأمامية عندما تعطس الواجهة الخلفية.
لماذا تتحدث Maison Code عن هذا
في Maison Code Paris، نعمل كضمير معمari لعملائنا. غالبًا ما نرث حزمًا “حديثة” تم بناؤها دون فهم أساسي للحجم.
نناقش هذا الموضوع لأنه يمثل نقطة تحول حاسمة في النضج الهندسي. التنفيذ الصحيح يميز MVP الهش عن منصة مؤسسية مرنة يمكنها التعامل مع حركة مرور الجمعة السوداء.
مشكلة “غير محدد ليس دالة”.
لمدة 20 عامًا، عاش مطورو الواجهة الأمامية والواجهة الخلفية في عزلة.
Backend Dev: “لقد قمت بتحديث واجهة برمجة تطبيقات المستخدم. وهي تُرجع الاسم الكامل بدلاً من الاسم_الأول.”
مطوّر الواجهة الأمامية: “حسنًا.” (نسي تحديث الكود).
الإنتاج: تحطم. user.first_name غير محدد.
وهذا ما يسمى فجوة التكامل.
يساعد التوثيق (Swagger/OpenAPI)، لكن التوثيق يكمن. لقد أصبح عفا عليه الزمن.
الحل الحديث هو السلامة الشاملة.
الكود نفسه يمنع أخطاء عدم التطابق هذه.
لماذا تناقش Maison Code بنية واجهة برمجة التطبيقات (API).
في Maison Code، نرث المشاريع التي تكون فيها طبقة API عبارة عن فوضى من نقاط نهاية السباغيتي.
/api/v1/get-user-final-final-2.
يؤدي هذا إلى إبطاء سرعة الميزة إلى حد الزحف.
نحن ننفذ بنيات آمنة للنوع.
نحن نقوم بتمكين الاستقلالية للواجهة الأمامية. لا ينبغي أن يضطر فريق الواجهة الأمامية إلى إزعاج فريق الواجهة الخلفية لإضافة حقل واحد إلى استجابة JSON.
نكتب عن هذا لأن الفرق القابلة للتطوير تعمل بموجب عقود قابلة للتطوير.
إذا كان مخططك فضفاضًا، فإن منتجك فضفاض.
1. المتنافسون
1. REST (مع OpenAPI)
الكلاسيكية.
- الإيجابيات: بسيط، وقابل للتخزين المؤقت (HTTP 200)، وعالمي.
- السلبيات: الجلب الزائد (الحصول على الكثير من البيانات) والجلب الناقص (عدد الطلبات +1).
- Modern Twist: استخدم OpenAPI (Swagger) لإنشاء أنواع TypeScript تلقائيًا.
npx openapi-typescript schema.json -o schema.d.ts. الآن، إذا تغيرت الواجهة الخلفية، فسيفشل بناء الواجهة الأمامية.
2. GraphQL
مستخدم الطاقة.
- الإيجابيات: يطلب العميل ما يحتاجه بالضبط.
الاستعلام { المستخدم { الاسم، الصورة الرمزية (الحجم: صغير) } } - السلبيات: التخزين المؤقت المعقد (كل شيء هو POST 200)، والتعقيد (المحللون، ومحملو البيانات).
- الأفضل لـ: التطبيقات المعقدة ذات الرسوم البيانية الثقيلة (الشبكات الاجتماعية ولوحات المعلومات) وعمليات تكامل نظام إدارة المحتوى (CMS) بدون رأس (Shopify وContentful).
3. tRPC (استدعاء الإجراء عن بعد لـ TypeScript)
شيطان السرعة.
- السياق: إذا كنت تمتلك كلاً من الواجهة الأمامية والخلفية (على سبيل المثال، Next.js Monorepo).
- السحر: يمكنك استيراد وظيفة الواجهة الخلفية مباشرةً إلى رمز الواجهة الأمامية.
// الخلفية تصدير const appRouter = جهاز التوجيه({ getUser: publicProcedure.query(() => { المعرف: 1، الاسم: 'Alex' }) }); // الواجهة الأمامية const user = trpc.getUser.useQuery(); console.log(user.data.name); // كتبت! - لا يوجد مخطط API. الكود * هو * المخطط.
- السلبيات: مغلق في TypeScript monorepos.
2. النمط: BFF (الواجهة الخلفية للواجهة الأمامية)
في بنيات الخدمات الصغيرة، لا تريد أن تستدعي الواجهة الأمامية 10 خدمات متميزة (خدمة المستخدم، خدمة سلة التسوق، خدمة المنتج). إنها بطيئة (10 رحلات ذهابًا وإيابًا) وفوضوية. الحل: طبقة BFF (عادةً مسارات GraphQL أو Next.js API). تقوم الواجهة الأمامية باستدعاء BFF مرة واحدة. يستدعي BFF الخدمات العشرة، ويجمع البيانات، ويزيل الأسرار، ويرسل JSON نظيفًا. وهذا يسمح للواجهة الأمامية بأن تكون “غبية” والواجهة الخلفية “معقدة” دون الإضرار بالأداء.
3. التحقق من صحة المدخلات: Zod
لا تثق بالعميل أبدًا. سواء كنت تستخدم REST أو GraphQL، يجب عليك التحقق من صحة المدخلات. Zod هو المعيار.
استيراد {z} من 'zod'؛
مخطط المستخدم الثابت = z.object({
البريد الإلكتروني: z.string().email()،
العمر: z.number().min(18)
});
app.post('/user', (req, res) => {
نتيجة const = UserSchema.safeParse(req.body);
إذا (! نتيجة. النجاح) {
إرجاع res.status(400).json(result.error);
}
// آمن للمتابعة
});
يمكن مشاركة مخطط Zod هذا مع الواجهة الأمامية لإنشاء منطق التحقق من صحة النموذج تلقائيًا (باستخدام “react-hook-form”).
4. طبقة الاتحاد (أبولو)
بالنسبة لتطبيقات المؤسسات، لا يكفي خادم GraphQL واحد. لديك “فريق المنتج” في برلين و”فريق الدفع” في نيويورك. لا يمكنهم مشاركة قاعدة بيانات واحدة. الحل: اتحاد GraphQL. يقوم كل فريق ببناء الرسم البياني الفرعي الخاص به. تقوم “البوابة” بجمعهم معًا في “رسم بياني فائق” واحد. تستعلم الواجهة الأمامية عن البوابة. يبدو وكأنه واجهة برمجة تطبيقات واحدة، ولكنه مدعوم بـ 50 خدمة صغيرة. هذه هي بنية Netflix وAirbnb.
5. استراتيجيات التعامل مع الأخطاء
“200 موافق” ولكن الأخطاء: ["غير موجود"]. هذا هو فخ GraphQL.
الاستراتيجية:
- أخطاء الشبكة: (DNS، 500s). أعد المحاولة مع التراجع الأسي.
- أخطاء منطقية: (لم يتم العثور على المستخدم). قم بإرجاع نوع لاغٍ أو نوع اتحاد.
وهذا يفرض على الواجهة الأمامية التعامل مع حالة الخطأ بشكل صريح في التعليمات البرمجية.Union UserResult = مستخدم | لم يتم العثور على مستخدم | تم رفض الإذنif (result.__typename === 'UserNotFound') ...معالجة الأخطاء من النوع الآمن.
6. استراتيجيات التخزين المؤقت (التي لا معنى لها أثناء إعادة التحقق)
يتم تخزين REST مؤقتًا بسهولة عبر رؤوس HTTP (التحكم في ذاكرة التخزين المؤقت: max-age=3600).
GraphQL أصعب.
نحن نستخدم Stale-While-Revalidate (SWR) على العميل (TanStack Query).
- عرض البيانات المخزنة مؤقتًا على الفور (قديمة).
- جلب بيانات جديدة في الخلفية (إعادة التحقق).
- قم بتحديث واجهة المستخدم إذا تم تغييرها. وهذا يجعل التطبيق يبدو “فوريًا”، حتى لو كانت الشبكة بطيئة.
7. الطبقة الأمنية (تحديد السعر وJWT)
واجهة برمجة التطبيقات بدون أمان هي باب مفتوح. ** تحديد المعدل **: منع DDoS.
- استخدم “upstash/ratelimit” (Redis) على الحافة.
- “10 طلبات لكل 10 ثوانٍ لكل IP”. المصادقة:
- التوقف عن استخدام ملفات تعريف الارتباط لواجهات برمجة التطبيقات. استخدم JWT (JSON Web Tokens) في رأس
Authorization: Bearer. - عديمي الجنسية. قابلة للتطوير.
- ولكن تأكد من التعامل مع Token Rotation (تحديث الرموز) بشكل آمن. التحقق:
- تعقيم المدخلات ضد حقن SQL (استخدم ORMs).
- تعقيم المخرجات ضد XSS.
8. تكامل الهجرة القديمة (الشكل الخانق)
لديك واجهة برمجة تطبيقات قديمة متجانسة (Java/PHP). تريد واجهة برمجة تطبيقات Node.js حديثة. لا تعيد كتابتها كلها مرة واحدة. سوف تفشل. استخدم نمط التين الخانق.
- ضع بروكسي (Nginx/Cloudflare) في المقدمة.
- قم بتوجيه
/api/v1/usersإلى واجهة برمجة التطبيقات الجديدة. - قم بتوجيه كل شيء آخر إلى Legacy API.
- قم بترحيل نقاط النهاية ببطء واحدة تلو الأخرى.
- قم بإيقاف تشغيل Legacy API عندما تنخفض حركة المرور إلى الصفر. يسمح لك هذا بشحن القيمة على الفور دون إعادة كتابة “الانفجار الكبير”.
9. المستندات كرمز (معيار الشريط)
كيف يحافظ Stripe على مستنداته بشكل جيد؟ يقومون بإنشائها من الكود. لا تكتب مستندات API في Word أو Confluence. اكتبها في المخطط.
- OpenAPI: أضف حقول “الوصف” إلى YAML الخاص بك.
- GraphQL: أضف
""" سلاسل مستندات """إلى مخططك. - الأدوات: استخدم Scalar أو Redoc لعرض مستندات HTML جميلة من المخطط.
- CI/CD: نشر المستندات تلقائيًا عند كل عملية دمج. المستندات القديمة أسوأ من عدم وجود مستندات.
10. وجهة نظر المتشكك
“GraphQL ميت. فقط استخدم الجلب.”
نقطة مضادة:
GraphQL على قيد الحياة وبصحة جيدة في المؤسسة.
يعمل عليه Shopify وGitHub وFacebook.
تعمل ميزة “الجلب فقط” للمدونات.
لا يعمل هذا مع صفحة منتج التجارة الإلكترونية التي تحتاج إلى السعر والمتغيرات والمخزون والمراجعات والتوصيات وحالة قائمة أمنيات المستخدم في طلب واحد.
إذا قمت بذلك باستخدام REST، فسيكون لديك إما 6 طلبات (بطيئة) أو نقطة نهاية واحدة هائلة /get-product-page-data (غير قابلة للصيانة).
GraphQL يحل مشكلة التنسيق.
11. حركة المرور الداخلية: مخازن البروتوكول المؤقتة (gRPC)
JSON قابل للقراءة من قبل الإنسان. كما أنها بطيئة.
يقوم بتكرار المفاتيح: {"name": "alex"، "age": 10}. يتم إرسال “الاسم” على السلك في كل مرة.
gRPC يستخدم Protobuf (ثنائي).
يرسل 0x12 0x04 0x61 0x6c 0x65 0x78.
إنه أصغر بنسبة 30% وأسرع بـ 5 مرات في التحليل.
نحن نستخدم gRPC للاتصال الداخلي بين الخدمات (الخدمات الصغيرة).
نحن نستخدم GraphQL/JSON للاتصال من العميل إلى الخادم.
الأداة المناسبة للوظيفة المناسبة.
12. مشكلة N+1 (برامج تحميل البيانات)
قاتل GraphQL الكلاسيكي.
الاستعلام: المستخدمون { المشاركات { العنوان } }.
- 1 استعلام للمستخدمين (اختر * من المستخدمين).
- 100 استعلام عن المشاركات (اختر * من المشاركات حيث user_id = 1…100).
- الإجمالي: 101 مكالمات DB.
الحل: محمل البيانات.
يقوم بتجميع 100 طلب في واحد.
اختر * من المشاركات التي يوجد فيها معرف المستخدم (1، 2، ... 100). وهذا يقلل من تحميل قاعدة البيانات بنسبة 99%. إذا كنت لا تستخدم DataLoaders، فسوف يذوب خادم GraphQL الخاص بك.
13. الاستنتاج
طبقة API هي الجهاز العصبي لتطبيقك. إذا كان ضعيفا (غير مكتوب، لم يتم اختباره)، يفشل الجسم. إذا كان قويًا (tRPC، اتحاد GraphQL)، يتحرك الجسم بخفة الحركة. توقف عن تخمين الأسماء بشكل صحيح. البدء في تنفيذها. العقد أولا. الكود الثاني.
واجهة برمجة التطبيقات (API) التي تكسر الواجهة الأمامية؟
نحن نصمم طبقات API-Safe API باستخدام GraphQL وtRPC لضمان أخطاء التكامل الصفري.