GraphQL مقابل REST في TypeScript: أيهما تختار لمشروعك

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

GraphQL مقابل REST في TypeScript: مبارزة العمالقة أم اختيار حسب المهمة؟

\n\n

عندما تكتب بلغة TypeScript، تصبح مسألة بنية الخادم أكثر إلحاحًا. لا تريد فقط "أن يعمل"، بل تريد أن تطير الأنواع، وأن تُلتقط الأخطاء في مرحلة التجميع، وأن يكون الكود قابلاً للتنبؤ. وهنا يقف المطور أمام خيار أبدي: REST المُختبر عبر الزمن أم GraphQL المرن والعصري؟ كلتا التقنيتين تتعاملان بشكل ممتاز مع TypeScript، لكن كل منهما تملي أسلوبها الخاص في التطوير.

\n\n

في هذه المقالة، لن نطيل الحديث أو نكرر الحقائق البديهية. سنقوم بتحليل GraphQL مقابل REST في TypeScript من خلال أمثلة محددة، مع الكود، ونقاط الضعف، والسيناريوهات التي يتفوق فيها أحد النهجين على الآخر. هيا بنا!

\n\n

REST: الصديق القديم الذي لا يخيب

\n\n

REST (نقل الحالة التمثيلية) هو أسلوب معماري حيث يكون لكل مورد (مستخدم، منشور، تعليق) عنوان URL خاص به. تطلب /api/users/1 وتحصل على المستخدم. بسيط وقابل للتنبؤ. في مشاريع TypeScript، غالبًا ما يتم تنفيذ REST عبر Express أو Fastify أو NestJS.

\n\n

التصنيف في REST مع TypeScript

\n

الألم الرئيسي في REST هو ضعف الارتباط بين الخادم والواجهة الأمامية. ترسل JSON، وتتساءل الواجهة الأمامية: "ماذا جاء؟". ينقذ TypeScript الموقف من خلال الأنواع المشتركة أو OpenAPI (Swagger).

\n\n

مثال: خادم Express مع TypeScript

\n\n
import express, { Request, Response } from 'express';\n\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nconst app = express();\napp.get('/api/users/:id', (req: Request, res: Response) => {\n  const user: User = { id: +req.params.id, name: 'Alice', email: 'alice@example.com' };\n  res.json(user);\n});\n
\n\n

الواجهة الأمامية (fetch):

\n\n
interface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nasync function getUser(id: number): Promise<User> {\n  const res = await fetch(`/api/users/${id}`);\n  return res.json() as Promise<User>;\n}\n
\n\n

المشكلة: إذا غيّر الخادم هيكل User، فإن الواجهة الأمامية لن تعلم بذلك إلا في وقت التشغيل. الأنواع في الواجهة الأمامية هي مجرد نسخة. الحل: توليد الأنواع من مواصفات OpenAPI.

\n\n

إيجابيات REST في TypeScript

\n
    \n
  • سهولة التخزين المؤقت: يعمل تخزين HTTP المؤقت (CDN، المتصفح) بشكل افتراضي.
  • \n
  • هيكل واضح: URL = مورد، الطرق = إجراءات (GET, POST, PUT, DELETE).
  • \n
  • دعم واسع: أي عميل (متصفح، curl، Postman) يفهم REST.
  • \n
  • عتبة دخول منخفضة: حتى المبتدئ سيفهمه في ساعة.
  • \n
\n\n

سلبيات REST

\n
    \n
  • Over-fetching و Under-fetching: إما تسحب حقولًا إضافية أو تقوم بعدة طلبات.
  • \n
  • هيكل صارم: للحصول على المستخدم + منشوراته، تحتاج إلى طلبين أو حلول بديلة (حقل expand).
  • \n
  • تصنيف ضعيف: بدون OpenAPI، الأنواع في العميل هي مجرد "وعد شرفي".
  • \n
\n\n

GraphQL: المرونة والتحكم

\n\n

GraphQL هي لغة استعلام تمنح العميل الحق في تحديد البيانات التي يريد الحصول عليها بنفسه. نقطة نهاية واحدة (/graphql)، طلب واحد - وتحصل بالضبط على ما طلبت. TypeScript و GraphQL هما ثنائي مثالي: يتم إنشاء الأنواع تلقائيًا من المخطط.

\n\n

التصنيف في GraphQL مع TypeScript

\n

أولاً، يتم كتابة المخطط (SDL):

\n\n
type User {\n  id: ID!\n  name: String!\n  email: String!\n  posts: [Post!]!\n}\n\ntype Post {\n  id: ID!\n  title: String!\n  content: String!\n}\n\ntype Query {\n  user(id: ID!): User\n}\n
\n\n

ثم يتم إنشاء الأنواع (عبر graphql-codegen):

\n\n
// generated.ts\nexport type User = {\n  __typename?: 'User';\n  id: string;\n  name: string;\n  email: string;\n  posts: Array<Post>;\n};\n\nexport type Post = {\n  __typename?: 'Post';\n  id: string;\n  title: string;\n  content: string;\n};\n

                
                

المدونات

توصيات الكتب