كيف تنشئ واجهة برمجة تطبيقات GraphQL؟

ما هو غطاء GraphQL

في السنوات الأخيرة أصبح GraphQL خيارًا شائعًا لبناء واجهات برمجة التطبيقات المعقدة. هذا لأنه يزيل بعض قيود واجهات برمجة التطبيقات التقليدية REST ويجعل واجهة برمجة التطبيقات الخاصة بك أكثر مرونة وكفاءة.

في هذه المقالة، سنناقش GraphQL، ومزاياها وعيوبها، ومصطلحات GraphQL الرئيسية، ومقارنة واجهات برمجة تطبيقات GraphQL بواجهات برمجة تطبيقات REST. علاوة على ذلك، سنعلمك كيفية إنشاء واجهة برمجة تطبيقات GraphQL الخاصة بك على Back4app والاتصال بها من واجهة Next.js.

مقدمة GraphQL

GraphQL هي لغة استعلام ووقت تشغيل من جانب الخادم لتطوير واجهات برمجة التطبيقات (APIs). باستخدام GraphQL، يمكن للعملاء تحديد البيانات التي يحتاجونها بالضبط من واجهة برمجة التطبيقات، بدلاً من الاعتماد على الواجهة الخلفية لتوفير مجموعة ثابتة من البيانات.

GraphQL هو نهج حديث وفعال لبناء واجهات برمجة تطبيقات سريعة ومرنة. يحتوي على نظام نوع مدمج ويستند إلى مخطط قوي النمط يحدد البيانات المتاحة من خلال واجهة برمجة التطبيقات. وهي تدعم التحديثات والاشتراكات في الوقت الفعلي وتسمح للمطورين بجلب البيانات من مصادر بيانات متعددة. بالإضافة إلى ذلك، فإنه يسهّل تطوير واجهات برمجة التطبيقات من خلال منح المطورين القدرة على إهمال الحقول دون التأثير على الاستعلامات أو الطفرات الحالية.

يمكن استخدام GraphQL من بداية المشروع أو دمجها في واجهة برمجة تطبيقات حالية. تقوم بعض الشركات أيضًا بدمجها مع REST ثم ترحيلها خطوة بخطوة.

تم تطويره داخليًا بواسطة Facebook في عام 2012 ثم تم طرحه لاحقًا في عام 2015. وقد اكتسب GraphQL شعبية مع ظهور تطبيقات الصفحة الواحدة (SPAs) وتطبيقات الأجهزة المحمولة. ومنذ إطلاقه، تم اعتماده من قِبل العديد من عمالقة التكنولوجيا مثل GitHub وAirbnb وPinterest و Shopify.

GraphQL مقابل REST

GraphQL و REST هما منهجان شائعان لبناء واجهات برمجة تطبيقات الويب.

REST (نقل الحالة التمثيلية) هو أسلوب معماري برمجي يصف بنية الويب. تم تقديمه في عام 2000 وكان المعيار الفعلي لبناء واجهات برمجة تطبيقات الويب لأكثر من عقد من الزمان. ويستخدم أساليب HTTP مثل GET و POST و PUT و PATCH و PATCH و DELETE لمعالجة الموارد. يتم استضافة كل مورد في نقطة النهاية الخاصة به (راجع الصورة أدناه) وفي كل مرة نطلب فيها موردًا يتم إرجاع “مجموعة البيانات” بأكملها.

قدمت هذه البنية مشكلتين. الأولى هي الجلب الناقص (الحصول على بيانات قليلة جدًا) والجلب الزائد (الحصول على بيانات أكثر من اللازم). علاوة على ذلك، لا تسمح لنا واجهات برمجة تطبيقات REST بالاشتراك في تغييرات البيانات.

هنا يأتي دور GraphQL. يحتوي GraphQL على نقطة نهاية واحدة ويسمح لنا بالاستعلام عن البيانات من مصادر بيانات متعددة في طلب واحد. يسمح لنا بتحديد البيانات التي نحتاجها بالضبط. بالإضافة إلى ذلك، يسمح لنا GraphQL بالاشتراك في تغييرات البيانات دون الحاجة إلى استطلاع رأي الخادم. كما أنها تجعل واجهة برمجة التطبيقات الخاصة بنا أكثر قابلية للتنبؤ وموثقة ذاتيًا.

في النهاية، يعتمد الاختيار بين GraphQL و REST على المتطلبات المحددة لمشروعك. على الرغم من أن GraphQL رائع، إلا أنه قد يؤدي إلى الكثير من التعقيد للمشاريع البسيطة.

واجهة برمجة تطبيقات REST API مقابل واجهة برمجة تطبيقات GraphQL

مصطلحات GraphQL الشائعة

دعنا نلقي نظرة على بعض المصطلحات الشائعة التي قد تواجهها عند العمل مع GraphQL.

النوع

يحتوي GraphQL على نظام أنماط وهو مكتوب بقوة. يأتي مع بعض الأنواع القياسية المضمنة مثل Int و Float و String و Boolean، ولكنه يسمح لك أيضًا بتعريف أنواع مخصصة.

يمكن تعريف النوع المخصص على هذا النحو:

type User {
    username: String!
    password: String!
    friends: [User!]
}

المخطط

المخطط هو وصف للبيانات المتاحة من خلال واجهة برمجة تطبيقات GraphQL. وهو يتضمن أنواع الكائنات، وحقولها وأنواع البيانات المرتبطة بها، والعلاقات، والاستعلامات، والطفرات، والمزيد. عادة ما يتم تعريف المخطط باستخدام لغة تعريف المخطط (SDL).

مثال على المخطط

محلل

المحلل هو دالة تسترجع البيانات لحقل معين في استعلام GraphQL. الدوال المحللة مسؤولة عن جلب البيانات من مصدر بيانات وإرجاعها بالصيغة المتوقعة.

استعلام

الاستعلام هو طلب قراءة فقط للبيانات من واجهة برمجة تطبيقات GraphQL. يمكنك التفكير في الاستعلامات كطلبات GET في REST API.

مثال على ذلك:

query GetUser {
    user(id: "Wfx8o2AZrE") {
        id
        username
        fullName
    }
}

يُرجع هذا الاستعلام قائمة بجميع المستخدمين.

الطفرات

الطفرة هي طلب لمعالجة البيانات في واجهة برمجة تطبيقات GraphQL. يمكنك التفكير في الطفرات على أنها طلبات POST/PUT/PATCH/DELETE في واجهة برمجة تطبيقات REST. يمكن أن تحدد الطفرات أيضًا البيانات التي يتم إرجاعها.

مثال على ذلك:

mutation CreateAuthor {
  createAuthor(input: {fields: {firstName: "William", lastName: "Shakespeare"}}) {
    author {
      id
      createdAt
    }
  }
}

تُنشئ هذه الطفرة مؤلفًا جديدًا وتُرجع مُعرّف المؤلف و” تم الإنشاء".

الاشتراك

الاشتراك هو طلب للحصول على تحديثات في الوقت الفعلي من واجهة برمجة تطبيقات GraphQL. تسمح الاشتراكات للعملاء بتلقي التحديثات بمجرد توفرها، دون الحاجة إلى استطلاع رأي الخادم.

مثال على ذلك:

subscription OnPostCreate($postID: ID!) {
  userAdded(postID: $postID) {
    id
    user
    content
  }
}

يتم استدعاء هذا الاشتراك عند إنشاء منشور جديد.

كيف يعمل GraphQL؟

لتنفيذ واجهة برمجة تطبيقات GraphQL يجب عليك تنفيذ الخطوات التالية:

  1. وصف بياناتك باستخدام مخطط
  2. ربط المحللات بمصادر البيانات
  3. كتابة الاستفسارات والطفرات
  4. احصل على نتائج متوقعة

وباستخدام Back4app أو خدمة مشابهة سيتم استخلاص معظم هذا العمل. أثناء قيامك بإنشاء نماذج قاعدة البيانات سيقوم Back4app تلقائيًا بإنشاء مخطط GraphQL والوثائق. المزيد عن هذا في الجزء العملي من البرنامج التعليمي.

ما هي مزايا GraphQL؟

من السهل تعلُّم GraphQL، ويمكن للمستخدمين تجميع البيانات من مصادر متعددة، وهي لغة حديثة لواجهة برمجة التطبيقات الخاصة بك.

المخطط

تعتمد واجهة برمجة GraphQL API على مخطط مطبوع بقوة. وهذا يسمح لك باكتشاف أخطاء النوع والأخطاء في وقت التحويل البرمجي وليس في وقت التشغيل. وعلاوة على ذلك، فإن واجهات برمجة تطبيقات GraphQL هي واجهات برمجة تطبيقات GraphQL استبطانية، مما يعني أنها يمكن أن توفر معلومات عن نفسها دون الاعتماد على أي وثائق خارجية.

مرونة وكفاءة في جلب البيانات

واجهات برمجة تطبيقات GraphQL مرنة للغاية لأنها تسمح للعملاء بتحديد ما يحتاجون إليه بالضبط. هذا يحل مشكلة الجلب الناقص والجلب الزائد ويقلل من عدد طلبات واجهة برمجة التطبيقات. يؤدي تقليل طلبات واجهة برمجة التطبيقات إلى أداء أفضل.

تحديثات واجهة برمجة التطبيقات

باستخدام GraphQL، يمكنك دمج الحقول والأنواع الجديدة بسلاسة دون التأثير على الاستعلامات الحالية. يمكن أيضًا إخفاء الحقول المهملة والقديمة من الأدوات. توفر واجهات برمجة تطبيقات GraphQL للتطبيقات وصولاً مستمرًا إلى ميزات جديدة وتشجع على تطوير كود خادم أنظف وأكثر استدامة.

مصدر واحد للحقيقة

يقوم مخطط GraphQL بتعيين مصدر واحد للحقيقة في تطبيق GraphQL. وهو يوفر للمؤسسة طريقة سهلة لإدارة واجهة برمجة التطبيقات بالكامل.

امتدادات GraphQL

GraphQL مدعوم بمجتمع ضخم من مطوري GraphQL ويأتي مع العديد من الإضافات مفتوحة المصدر. تعمل الامتدادات على تبسيط بعض مهام واجهة برمجة التطبيقات الشائعة مثل ترقيم الصفحات، والتخزين المؤقت، ومراقبة الأداء، وما إلى ذلك.

ما هي عيوب GraphQL؟

التعقيد

يقوم GraphQL بتحويل الكثير من عمل استعلام البيانات إلى جانب الخادم، مما يجعل الخلفية أكثر تعقيدًا. علاوة على ذلك، قد تتطلب لغة الاستعلام وتعريفات المخطط مزيدًا من التخطيط والصيانة مقدمًا.

منحنى التعلّم

يحتوي GraphQL على منحنى تعليمي أكثر حدة من REST. بالإضافة إلى ذلك، عادةً ما يكون مطورو GraphQL أكثر تكلفة وأصعب في العثور على مطوري REST.

الافتقار إلى التوحيد القياسي

أحد الانتقادات الرئيسية لـ GraphQL هو الافتقار إلى التوحيد القياسي في تنفيذه. تحتوي واجهات برمجة تطبيقات REST على مجموعة راسخة من المبادئ وأفضل الممارسات بينما توفر وثائق GraphQL بعض النصائح العامة فقط حول كيفية تنفيذ الأشياء. وهذا يمكن أن يؤدي إلى تناقضات وارتباك في كيفية تصميم واستخدام واجهات برمجة تطبيقات GraphQL.

الأمن

إن الشيء الرائع في GraphQL هو أن العملاء يمكنهم طلب ما يحتاجون إليه بالضبط، ولكن من ناحية أخرى، قد يكون ذلك خطرًا أمنيًا محتملاً. من المهم التحقق من صحة مدخلات المستخدم وتعقيمها بشكل صحيح لمنع تنفيذ الاستعلامات الضارة.

كيف تنشئ واجهة برمجة تطبيقات GraphQL؟

يبحث هذا القسم من المقالة في كيفية إنشاء واجهة برمجة GraphQL API باستخدام Back4app والاتصال بها من واجهة Next.js.

المتطلبات الأساسية

  • خبرة في JavaScript ES6
  • خبرة في React و Next.js
  • الفهم الأساسي ل GraphQL

ما هو تطبيق Back4app؟

Back4app هو حل Back4app كخدمة (BaaS) استثنائي يعمل على رأس البرامج مفتوحة المصدر. وتوفر المنصة مجموعة واسعة من الميزات التي تتيح للمستخدمين تطوير أسهل وأسرع لتطبيقات الويب والهاتف المحمول. وهي تتيح للشركات التركيز على منطق أعمالها دون الحاجة إلى القلق بشأن الواجهة الخلفية أو البنية التحتية الأساسية.

يأتي Back4app مع لوحة تحكم سهلة الاستخدام مليئة بالميزات وواجهة سطر أوامر (CLI). كما يوفر أيضًا مجموعات تطوير البرمجيات (SDKs) للعديد من الأدوات الشائعة مثل Node.js وFlutter وReact Native وAndroid وAngular وiOS وغيرها.

يتبع Back4app نموذج تسعير مباشر يمكن أن يلبي احتياجات أي تطبيق. كما أنها تقدم خطة مجانية (لا تتطلب بطاقة ائتمان) وهي رائعة للاختبار والنماذج الأولية.

هل تريد معرفة المزيد عن Back4app؟ اطلع على لماذا تستخدم Back4app؟

مقدمة المشروع

سنقوم ببناء تطبيق ويب TODO بسيط على الويب. سيتكون التطبيق من جزأين: الواجهة الخلفية والواجهة الأمامية. سيتم تشغيل الواجهة الخلفية بواسطة واجهة برمجة تطبيقات GraphQL وسيتم نشرها على Back4app. من ناحية أخرى، ستتم كتابة الواجهة الأمامية بلغة TypeScript باستخدام إطار عمل Next.js. لربط الواجهة الأمامية بالواجهة الخلفية سنستخدم عميل Apollo Client.

سيبدو التطبيق النهائي بهذا الشكل:

معاينة مشروع back4app-graphql معاينة المشروع

الواجهة الخلفية

إنشاء تطبيق Back4app

لمتابعة الخطوات التالية، ستحتاج إلى أن يكون لديك حساب Back4app. إذا كان لديك حساب بالفعل، يُرجى تسجيل الدخول. وإلا فلا تتردد في التسجيل للحصول على حساب مجاني.

من أجل استخدام Back4app، فإن الخطوة الأولى هي إنشاء تطبيق. بمجرد تسجيل الدخول إلى لوحة التحكم الخاصة بك، ستتمكن من عرض قائمة بتطبيقاتك الحالية. لإنشاء تطبيق جديد، انقر على “إنشاء تطبيق جديد”.

إنشاء تطبيق Back4app Back4app

بما أننا ننشئ واجهة برمجة تطبيقات GraphQL، اختر خيار “الواجهة الخلفية كخدمة”، وحدد اسمًا فريدًا لتطبيقك. بالإضافة إلى ذلك، اختر “NoSQL” كنوع قاعدة البيانات.

انتظر بصبر حتى يقوم Back4app بتهيئة كل ما هو مطلوب لتطبيقك، بما في ذلك قاعدة البيانات وطبقة التطبيق والتوسع والنسخ الاحتياطي والأمان.

بعد اكتمال الإعداد، سيتم توجيهك إلى لوحة تحكم التطبيق الخاص بك.

إنشاء تطبيق Back4app Back4app

تعريف نماذج قواعد البيانات

بما أننا نبني تطبيق TODO بسيط، سنحتاج إلى نموذج قاعدة بيانات واحد فقط.

للبدء، انتقل إلى لوحة تحكم Back4app وحدد خيار “قاعدة البيانات” في الشريط الجانبي. من هناك، اختر “إنشاء فئة”، وأطلق عليها اسم “مهمة”. تأكد من تحديد “تمكين القراءة والكتابة العامة” ثم انقر على “إنشاء فئة وإضافة أعمدة”.

نموذج تعريف Back4app Back4app

قم بتضمين الأعمدة التالية:

+-----------+------------------+---------------+----------+
| Data type | Name             | Default value | Required |
+-----------+------------------+---------------+----------+
| String    | name             | <leave blank> | yes      |
+-----------+------------------+---------------+----------+
| String    | description      | <leave blank> | no       |
+-----------+------------------+---------------+----------+
| Boolean   | isDone           | false         | no       |
+-----------+------------------+---------------+----------+

بعد إنشاء نموذج قاعدة البيانات الخاص بك ستلاحظ أنه تمت إضافة أربعة أعمدة لقاعدة البيانات تلقائيًا:

  1. معرف الكائن هو المفتاح الأساسي للكائن الخاص بك
  2. محدثة في هو الطابع الزمني لآخر تحديث
  3. تم الإنشاء في هو الطابع الزمني للإنشاء
  4. يُعرّف ACL “قائمة التحكم في الوصول”

ضعها في اعتبارك لأننا سنحتاج إليها لاحقًا في البرنامج التعليمي عند العمل على استعلامات GraphQL والطفرات.

للتعرف على لوحة تحكم Back4app حاول إضافة نموذجين من المهام، على سبيل المثال:

+-----------------+----------------------------------------+--------+
| name            | description                            | isDone |
+-----------------+----------------------------------------+--------+
| GraphQL backend | Create a GraphQL backend via Back4app. | false  |
+-----------------+----------------------------------------+--------+
| Learn GraphQL   | Learn the basics of GraphQL.           | true   |
+-----------------+----------------------------------------+--------+

وحدة تحكم واجهة برمجة GraphQL API

تسمح لنا وحدة تحكم GraphQL API باختبار استعلامات GraphQL والطفرات قبل تنفيذها في التعليمات البرمجية. للوصول إلى وحدة التحكم اختر “API” على الشريط الجانبي ثم “وحدة التحكم > GraphQL”.

Back4app GraphQL Console

وحدة التحكم سهلة الاستخدام للغاية. على الجانب الأيسر، يمكننا إدخال استفساراتنا وطفراتنا المخصصة ثم يتم عرض النتائج على اليمين.

للتحقق مما إذا كان كل شيء يعمل قم بتشغيل الاستعلام التالي:

query CheckHealth {
    health
}

يجب أن تحصل على استجابة JSON التالية:

{
  "data": {
    "health": true
  }
}

أحد الأشياء الرائعة في Back4app هو أنه يعتمد على Parse. عندما أنشأنا نموذج قاعدة البيانات الخاصة بنا قام Parse تلقائيًا بتكوين GraphQL لنا. يتضمن ذلك إنشاء مخطط GraphQL، والمستندات، وما إلى ذلك.

دعنا نحاول سرد المهام وتفاصيلها من قاعدة البيانات:

query GetTasks {
  tasks {
    count
    edges {
      node {
        id
        name
        description
        isDone
      }
    }
  }
}

يجب أن تحصل على رد مماثل:

{
  "data": {
    "tasks": {
      "count": 2,
      "edges": [
        {
          "node": {
            "id": "VGFzazpXQkJzSkRtV2xU",
            "name": "GraphQL backend",
            "description": "Create a GraphQL backend via Back4app.",
            "isDone": false
          }
        },
        {
          "node": {
            "id": "VGFzazpnM2lhNzdwUXBp",
            "name": "Learn GraphQL",
            "description": "Learn the basics of GraphQL.",
            "isDone": true
          }
        }
      ]
    }
  }
}

يتم الحصول على كائن معين وإنشاء كائنات وتحديثها وما إلى ذلك بالمثل. لن أتطرق إلى الكثير من التفاصيل الآن لأنني سأشرح هذه الاستعلامات والطفرات لاحقًا في البرنامج التعليمي. بالإضافة إلى ذلك، تغطي مستندات Back4app هذه المواضيع بشكل جيد:

  1. إنشاء كائن
  2. الحصول على كائن
  3. العثور على الأشياء
  4. تحديث كائن
  5. حذف كائن
  6. المصادقة

هذا كل شيء بالنسبة لجزء الواجهة الخلفية. في القسم التالي، سنبدأ العمل على الواجهة الأمامية.

الواجهة الأمامية

إنشاء التطبيق التالي

أسهل طريقة لتهيئة مشروع Next.js هي استخدام الأداة المساعدة Create-next-app. افتح جهازك الطرفي وشغّل الأمر التالي:

$ yarn create next-app

√ What is your project named? ... back4app-graphql
√ Would you like to use TypeScript with this project? ... No
√ Would you like to use ESLint with this project? ... Yes
√ Would you like to use the `src/` directory with this project? ... No
√ Would you like to use the experimental `app/` directory with this project? ... No
√ What import alias would you like configured? ... @/*

Successfully created a Next.js app.

بعد ذلك، قم بتشغيل خادم التطوير:

$ yarn dev

انتقل إلى http://localhost:3000 وسترى صفحة الهبوط Next.js الافتراضية.

الصفحة المقصودة الافتراضية التالية

ChakraUI

لتسريع وتبسيط عملية بناء واجهة المستخدم/تجربة المستخدم سنستخدم ChakraUI. Chakra UI هي مكتبة مكونات بسيطة ونموذجية ويمكن الوصول إليها والتي تمنحك كل ما تحتاجه لبناء تطبيقات React الخاصة بك.

في حال واجهتك أي مشاكل ارجع إلى ChakraUI: الشروع في استخدام Next.js.

لتثبيته قم بتشغيله:

yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion

بعد ذلك، انتقل إلى _pages/app.tsx الخاص بك ولف تطبيقك ب ChakraProvider هكذا:

// pages/_app.tsx

import "../styles/globals.css";
import type {AppProps} from "next/app";
import {ChakraProvider} from "@chakra-ui/react";

export const theme = extendTheme({});

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default MyApp;

لا تنسى استيراد ChakraProvider:

import {ChakraProvider} from "@chakra-ui/provider";

لتجنب ومضات الألوان العشوائية تأكد من تحميل البرنامج النصي لوضع الألوان قبل المحتوى. للقيام بذلك يمكنك استخدام _document.js هكذا:

// pages/_document.tsx

import {ColorModeScript} from "@chakra-ui/react";
import { Html, Head, Main, NextScript } from "next/document";
import {theme} from "@/pages/_app";

export default function Document() {
  return (
    <Html lang='en'>
      <Head />
      <body>
        <ColorModeScript initialColorMode={theme.config.initialColorMode} />
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

رائع، لقد قمت بتثبيت ChakraUI بنجاح.

واجهة المستخدم

للمضي قدمًا، دعنا ننشئ واجهة المستخدم. سيحتوي تطبيق الويب الخاص بنا على الصفحتين التاليتين:

  1. / يعرض قائمة المهام
  2. إنشاء/عرض نموذج إنشاء المهام

ابدأ باستبدال الصفحات/index.tsx بالمحتويات التالية:

// pages/index.tsx

import type {NextPage} from "next";
import {
    Button, Card, CardBody, Container,
    Heading, HStack, Stack, Text, VStack
} from "@chakra-ui/react";
import Link from "next/link";

let data = {
  "tasks": {
    "count": 2,
    "edges": [
      {
        "node": {
          "id": "VGFzazpXQkJzSkRtV2xU",
          "name": "GraphQL backend",
          "description": "Create a GraphQL backend via Back4app.",
          "isDone": false
        }
      },
      {
        "node": {
          "id": "VGFzazpnM2lhNzdwUXBp",
          "name": "Learn GraphQL",
          "description": "Learn the basics of GraphQL.",
          "isDone": true
        }
      }
    ]
  }
};

const ListPage: NextPage = () => {

  const handleMarkAsDone = async (id: string, isDone: boolean) => {
    console.log("TODO: mark task as done and refetch");
  };

  const handleDelete = async (id: string) => {
    console.log("TODO: delete task and refetch");
  };

  return (
    <>
      <Container maxWidth="container.lg">
        <HStack w="fill" justifyContent="space-between" mt={8} mb={4}>
          <Heading as="h1" size="lg">back4app-graphql</Heading>
          <Link href="/create">
            <Button size="sm" colorScheme="blue">
              Create task
            </Button>
          </Link>
        </HStack>
        <VStack spacing={4}>
          {data.tasks.edges.map((edge) => {
            let task = edge.node;
            return (
              <Card key={task.id} w="100%">
                <CardBody>
                  <Stack direction="column">
                    <Heading as="h2" size="md">
                      {task.isDone ? "✔️" : "❌"}{" "}
                      {task.name}
                    </Heading>
                    <Text>
                      {task.description}
                    </Text>
                    <Stack direction="row" pt={2}>
                      <Button size="sm" colorScheme="blue" onClick={() => handleMarkAsDone(task.id, task.isDone)}>
                        Toggle done
                      </Button>
                      <Button size="sm" colorScheme="red" onClick={() => handleDelete(task.id)}>
                        Delete
                      </Button>
                    </Stack>
                  </Stack>
                </CardBody>
              </Card>
            );
          })}
        </VStack>
      </Container>
    </>
  );
};

export default ListPage;
  1. استخدمنا ChakraUI لتصميم واجهة المستخدم.
  2. يتم تحميل المهام حاليًا من المصفوفة الثابتة المسماة بيانات.
  3. سنستخدم لاحقًا التعامل مع dealMarkAsDone() والتعامل مع حذف() لإرسال طلبات واجهة برمجة GraphQL.

بعد ذلك، قم بإنشاء ملف create.tsx داخل مجلد الصفحات بالمحتويات التالية:

// pages/create.tsx

import type {NextPage} from "next";
import {
  Button, Card, CardBody, CardHeader, Container, FormControl,
  FormLabel, Heading, HStack, Input, Stack, Switch, Text
} from "@chakra-ui/react";
import Link from "next/link";
import {useState} from "react";
import {useRouter} from "next/router";

const CreatePage: NextPage = () => {
  const router = useRouter();

  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [isDone, setIsDone] = useState(false);

  const [formError, setFormError] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();

    if (!name || !description) {
      setFormError("Please enter the title and the description.");
      return;
    }

    console.log("TODO: call the GraphQL API and redirect");
  };

  return (
    <>
      <Container maxWidth="container.lg">
        <HStack w="fill" justifyContent="space-between" mt={8} mb={4}>
          <Heading as="h1" size="lg">back4app-graphql</Heading>
          <Link href="/">
            <Button size="sm" colorScheme="blue">
              View list
            </Button>
          </Link>
        </HStack>
        <Card>
          <CardHeader>
            <Stack direction="column">
              <Heading as="h2" size="md">Create task</Heading>
              <Text>
                Fill out the form and press &quot;Create&quot; to create a new task.
              </Text>
            </Stack>
          </CardHeader>
          <CardBody>
            <form onSubmit={handleSubmit}>
              <Stack direction="column">
                {formError && <Text color="red.500" fontWeight="bold">{formError}</Text>}
                <FormControl>
                  <FormLabel>Name</FormLabel>
                  <Input type="text" value={name} onChange={(event) => setName(event.target.value)}/>
                </FormControl>
                <FormControl>
                  <FormLabel>Description</FormLabel>
                  <Input type="text" value={description} onChange={(event) => setDescription(event.target.value)}/>
                </FormControl>
                <FormControl display="flex" alignItems="center">
                  <FormLabel mb="0">
                    Is done?
                  </FormLabel>
                  <Switch isChecked={isDone} onChange={() => setIsDone(!isDone)}/>
                </FormControl>
                <Button size="sm" colorScheme="blue" type="submit">Create task</Button>
              </Stack>
            </form>
          </CardBody>
        </Card>
      </Container>
    </>
  );
};

export default CreatePage;
  1. استخدمنا مرة أخرى مكونات ChakraUI لإنشاء واجهة المستخدم.
  2. لقد أنشأنا نموذج React متحكم به لإنشاء المهام.
  3. سيتم استخدام الدالة handleSubmit() لاحقًا لإرسال طلب واجهة برمجة التطبيقات.

أعد تشغيل خادم الويب الخاص بك وقم بزيارة تطبيق الويب الخاص بك على http://localhost:3000. يجب أن تشاهد المهمتين المشفرتين الثابتتين. بعد ذلك، انقر على “إنشاء مهمة” لرؤية نموذج إنشاء المهمة.

Back4app GraphQL إنشاء مهمة إنشاء تطبيق Back4app GraphQL

عميل GraphQL

للاتصال بواجهة GraphQL API من الواجهة الأمامية تحتاج أولاً إلى تثبيت عميل GraphQL. أقترح عليك استخدام عميل Apollo Client، حيث أنه سهل الإعداد، وغير متعلق بالعملاء، ولا يتطلب الكثير من الإجراءات.

ابدأ بتثبيت @apollo/client و Graphql:

$ yarn add @apollo/client graphql

لتهيئة العميل ستحتاج إلى تقديم بيانات اعتماد Back4app API الخاصة بك. أسهل طريقة للحصول على بيانات الاعتماد الخاصة بك هي الانتقال إلى وحدة تحكم GraphQL الخاصة بك وتدوين العناوين.

بيانات اعتماد Back4app GraphQL

نظرًا لأنك لا تريد كشف مفاتيح واجهة برمجة التطبيقات في الشيفرة المصدرية قم بإنشاء ملف .env.local في جذر المشروع بالمحتويات التالية:

# .env.local

NEXT_PUBLIC_PARSE_APPLICATION_ID=<YOUR_PARSE_APP_ID>
NEXT_PUBLIC_PARSE_MASTER_KEY=<YOUR_PARSE_MASTER_KEY>
NEXT_PUBLIC_PARSE_CLIENT_KEY=<YOUR_PARSE_CLIENT_KEY>

بعد ذلك، انتقل إلى الصفحات/التطبيق.tsx وقم بتهيئة عميل Apollo، ثم قم بلف تطبيقك باستخدام ApolloProvider هكذا:

// pages/_app.tsx

// ...
import {ApolloClient, ApolloProvider, InMemoryCache} from "@apollo/client";

const client = new ApolloClient({
  uri: "https://parseapi.back4app.com/graphql",
  headers: {
    "X-Parse-Application-Id": process.env.NEXT_PUBLIC_PARSE_APPLICATION_ID,
    "X-Parse-Master-Key": process.env.NEXT_PUBLIC_PARSE_MASTER_KEY,
    "X-Parse-Client-Key": process.env.NEXT_PUBLIC_PARSE_CLIENT_KEY,
  },
  cache: new InMemoryCache(),
});

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <ApolloProvider client={client}>
        <Component {...pageProps} />
      </ApolloProvider>
    </ChakraProvider>
  );
}

انتظر حتى تتم إعادة ترجمة الواجهة الأمامية ثم قم بزيارة تطبيق الويب الخاص بك وتحقق من وحدة التحكم بحثًا عن أي أخطاء. عدم وجود أخطاء يعني أن الاتصال كان ناجحًا.

استعلامات GraphQL والطفرات

آخر ما عليك فعله هو تحديد استعلامات وطفرات GraphQL الخاصة بك ثم استدعائها من شيفرة React الخاصة بك.

لتمكين المساعدة برمز GraphQL في IDE الخاص بك، انتقل إلى وحدة تحكم Back4app GraphQL، وحدد “المخطط” على الشريط الجانبي، وقم بتنزيله بصيغة SDL. ثم قم بإنشاء ملف جديد باسم schema.graphql في جذر المشروع والصق محتويات SDL.

أولاً، انتقل إلى الصفحات/index.tsx وأضف الاستعلامات التالية بعد عمليات الاستيراد:

// pages/index.tsx

const GET_TASKS = gql`
  query GetTasks {
    tasks {
      count
      edges {
        node {
          id
          name
          description
          isDone
        }
      }
    }
  }
`;

const UPDATE_TASK = gql`
  mutation UpdateTask($id: ID!, $isDone: Boolean!) {
    updateTask(input: { id: $id, fields: { isDone: $isDone } }) {
      task {
        isDone
        updatedAt
      }
    }
  }
`;

const DELETE_TASK = gql`
  mutation DeleteTask($id: ID!) {
    deleteTask(input: { id: $id }) {
      task {
        id
      }
    }
  }
`;

هذه الاستعلامات الثلاثة لا تحتاج إلى شرح. يُرجِع الاستعلام الأول قائمة بجميع المهام، والثاني يُحدِّث خاصية isDone لمهمة محددة، والثالث يحذف مهمة محددة.

بعد ذلك، قم بتعديل الجزء العلوي من ListPage هكذا:

// pages_index.tsx

// ...

const ListPage: NextPage = () => {

  const {loading, error, data, refetch} = useQuery(GET_TASKS);
  const [deleteTask] = useMutation(DELETE_TASK);
  const [updateTask] = useMutation(UPDATE_TASK);

const handleMarkAsDone = async (id: string, isDone: boolean) => {
    try {
      const updateTaskResponse = await updateTask({
        variables: {id: id, isDone: !isDone}
      });
      console.debug(updateTaskResponse);
      refetch();
    } catch (error) {
      console.error(error);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      const deleteTaskResponse = await deleteTask({
        variables: {id: id},
      });
      console.debug(deleteTaskResponse);
      refetch();
    } catch (error) {
      console.error(error);
    }
  };

  if (error) return <p>Oops, something went wrong.</p>;
  if (loading) return <Spinner/>;

  // ...
};

export default ListPage;
  1. لقد استخدمنا استخدام() لتنفيذ استعلام GET_TASKS وتخزين النتيجة.
  2. لقد استخدمنا استخدام الطفرات () لتعريف طفرات GraphQL.
  3. حدَّثنا التعامل مع (dealMarkAsDone()) و (dealDelete()) للاستفادة من خطافات الطفرات.

للمضي قدمًا، عدّل الصفحات/إنشاء.tsx بطريقة مشابهة:

const CREATE_TASK = gql`
  mutation CreateTask($name: String!, $description: String, $isDone: Boolean!) {
    createTask(
      input: {
        fields: { name: $name, description: $description, isDone: $isDone }
      }
    ) {
      task {
        id
      }
    }
  }
`;

const CreatePage: NextPage = () => {

  // ...

  const [createTask] = useMutation(CREATE_TASK);

  const handleSubmit = (event) => {
    event.preventDefault();

    if (!name || !description) {
      setFormError("Please enter the title and the description.");
      return;
    }

    createTask({
      variables: {name: name, description: description, isDone: isDone}
    }).then(response => {
      router.push("/");
    });
  };

  // ...
};

export default CreatePage;

لا تنسى الاستيراد:

import {gql, useMutation, useQuery} from "@apollo/client";

عظيم، هذا كل شيء!

أعد تشغيل خادم التطوير وقم بزيارة تطبيق الويب الخاص بك. تحقق مما إذا تم تحميل المهام من قاعدة البيانات، حاول إنشاء مهمة جديدة ووضع علامة على أنها منجزة وحذفها.

الخاتمة

في الختام، تعد GraphQL خيارًا جيدًا لبناء واجهات برمجة التطبيقات المعقدة نظرًا لقدراتها المرنة في الاستعلام واسترجاع البيانات بكفاءة. على الرغم من أنها تتمتع بالعديد من المزايا مقارنة بواجهة برمجة تطبيقات REST التقليدية، إلا أن هناك بعض العيوب التي يجب أن تضعها في الاعتبار عند بدء المشروع.

في هذه المقالة، ناقشنا مزايا وعيوب GraphQL، وقارناها مع واجهات برمجة التطبيقات REST، وقدمنا بعض المصطلحات الرئيسية ل GraphQL. يجب أن تكون الآن قادرًا على إنشاء واجهة برمجة تطبيقات GraphQL البسيطة الخاصة بك على Back4app والاتصال بها من واجهة JavaScript الأمامية.

يمكنك الحصول على الكود المصدري النهائي من GitHub repo.

الأسئلة الشائعة

ما هو GraphQL؟

GraphQL هي لغة استعلام وبيئة تشغيل من جانب الخادم لتطوير واجهات برمجة التطبيقات (APIs) قوية ومرنة.

ما هي الفروقات الرئيسية بين REST و GraphQL؟

REST هو نهج موحد وبسيط لبناء خدمات الويب، بينما يوفر GraphQL قدرات استعلام أكثر مرونة ويقضي على نقص البيانات أو زيادتها.

ما هي المصطلحات الشائعة الاستخدام في GraphQL؟

– Schema هو وصف للبيانات المتاحة من خلال GraphQL API.
– Resolver هو دالة تسترجع البيانات لحقل معين في استعلام GraphQL.
– Query هو طلب للقراءة فقط من GraphQL API.
– Mutation هو طلب لتعديل البيانات في GraphQL API.
– Subscription هو طلب لتحديثات فورية من GraphQL API.

كيف تبني GraphQL API؟

1. أنشئ حسابًا مجانيًا على Back4app.
2. صمّم نماذج قاعدة البيانات.
3. اكتب الاستعلامات وعمليات التعديل من خلال وحدة تحكم Back4app GraphQL API.
4. ثبّت عميل GraphQL (مثل Apollo أو Relay) في مشروع الواجهة الأمامية.
5. فعّل العميل وتواصل مع GraphQL API.


Leave a reply

Your email address will not be published.