مقدمة إلى GraphQL: كيف تعمل وكيف تستخدمها

الصورة بواسطة مات دنكان على Unsplash

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

يمكنك أيضًا في GraphQL الحصول على موارد خادم متعددة في مكالمة واحدة بدلاً من إجراء مكالمات REST API متعددة.

يمكنك التحقق من https://graphql.org/ للحصول على قائمة كاملة بالمزايا.

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

سنستخدم GraphQL مع NodeJS في هذه المقالة.

الشروط المسبقة

قم بتثبيت NodeJS من هنا: https://nodejs.org/en/.

كيفية استخدام GraphQL مع NodeJs

GraphQL يمكن استخدامها مع لغات متعددة. سنركز هنا على كيفية استخدام GraphQL مع JavaScript باستخدام NodeJS.

إنشاء مجلد يسمى graphql-with-nodejs. انتقل إلى مجلد المشروع وتشغيل npm init لإنشاء مشروع NodeJS. ويرد الأمر لهذا أدناه.

مؤتمر نزع السلاح graphql مع nodejs
npm init

تثبيت التبعيات

قم بتثبيت Express باستخدام الأمر التالي:

npm تثبيت صريح

قم بتثبيت GraphQL باستخدام الأمر التالي. سنقوم بتثبيت GraphQL و GraphQL لـ Express.

npm تثبيت express-graphql graphql

كود NodeJS

قم بإنشاء ملف يسمى server.js داخل المشروع وانسخ الرمز التالي فيه:

const express = require ('express') ؛
منفذ const = 5000 ؛
التطبيق const = express () ؛

app.get ('/ hello'، (req، res) => {
    res.send ( "مرحبا")؛
   }
)؛

app.listen (منفذ)؛
console.log (`Server Running at localhost: $ {port}`)؛

يحتوي الرمز أعلاه على نقطة نهاية HTTP GET واحدة تسمى / hello.

يتم إنشاء نقطة النهاية باستخدام Express.

الآن ، دعونا نقوم بتعديل هذا الرمز لتمكين GraphQL.

تمكين GraphQL في الكود

سيكون لدى GraphQL نقطة نهاية لعنوان URL واحد تسمى / graphql والتي ستتولى معالجة جميع الطلبات.

انسخ الكود التالي في server.js:

// الحصول على جميع المكتبات اللازمة
const express = require ('express') ؛
const graphqlHTTP = require ('express-graphql') ؛
const {GraphQLSchema} = require ('graphql') ؛

const {queryType} = require ('./ query.js') ؛

// إعداد رقم المنفذ والتطبيق السريع
منفذ const = 5000 ؛
التطبيق const = express () ؛

 / / حدد المخطط
const schema = new GraphQLSchema ({query: queryType})؛

// إعداد خادم nodejs GraphQL
app.use ('/ graphql' ، graphqlHTTP ({
    المخطط: المخطط ،
    graphiql: صحيح ،
}))؛

app.listen (منفذ)؛
console.log (`GraphQL Server يعمل على المضيف المحلي: $ {port}`) ؛

دعنا نذهب من خلال هذا الرمز الآن.

graphqlHTTP يتيح لنا إعداد خادم GraphQL على / graphql url. إنه يعرف كيفية التعامل مع الطلب الوارد.

يتم هذا الإعداد في سطور التعليمات البرمجية التالية:

app.use ('/ graphql' ، graphqlHTTP ({
    المخطط: المخطط ،
    graphiql: صحيح ،
}))؛

الآن ، دعونا نستكشف المعلمات داخل graphqlHTTP.

graphiql

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

مخطط

يحتوي GraphQL على نقطة نهاية خارجية واحدة / graphql. يمكن أن تحتوي نقطة النهاية هذه على نقاط نهاية أخرى متعددة تقوم بأشياء مختلفة. سيتم تحديد نقاط النهاية هذه في المخطط.

المخطط سيفعل أشياء مثل:

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

يتم تعريف المخطط كما يلي في التعليمات البرمجية:

const schema = new GraphQLSchema ({query: queryType})؛

يمكن أن يحتوي المخطط على أنواع الاستعلام وكذلك الطفرات. سوف تركز هذه المقالة فقط على نوع الاستعلام.

سؤال

يمكنك أن ترى في المخطط أنه تم تعيين الاستعلام إلى queryType.

نقوم باستيراد queryType من ملف query.js باستخدام الأمر التالي:

const {queryType} = require ('./ query.js') ؛

query.js هو ملف مخصص سنقوم بإنشائه قريبًا.

الاستعلام هو المكان الذي نحدد فيه نقاط النهاية للقراءة فقط في المخطط.

قم بإنشاء ملف يسمى query.js في المشروع وانسخ الكود التالي فيه.

const {GraphQLObjectType ،
    GraphQLString
} = require ('graphql') ؛


/ / حدد الاستعلام
const queryType = جديد GraphQLObjectType ({
    الاسم: "الاستعلام" ،
    مجالات: {
        مرحبا: {
            النوع: GraphQLString ،

            حل: وظيفة () {
                عودة "مرحبا العالم" ؛
            }
        }
    }
})؛

export.queryType = queryType؛

شرح الاستعلام

يتم إنشاء queryType كـ GraphQLObjectType وإعطاء اسم الاستعلام.

الحقول هي حيث نحدد نقاط النهاية المختلفة.

حتى هنا نضيف نقطة نهاية واحدة تسمى مرحبا.

مرحبًا يحتوي على نوع من GraphQLString مما يعني أن نقطة النهاية هذه لها نوع إرجاع من السلسلة. النوع هو GraphQLString بدلاً من String لأن مخطط GraphQL هذا. لذلك مباشرة باستخدام سلسلة لن تعمل.

تشير دالة التصرف إلى التصرف الواجب تنفيذه عند استدعاء نقطة النهاية. الإجراء هنا هو إرجاع سلسلة "Hello World".

أخيرًا ، نقوم بتصدير querytype باستخدام export.queryType = queryType. هذا هو التأكد من أننا يمكن استيراده في server.js.

تشغيل التطبيق

قم بتشغيل التطبيق باستخدام الأمر التالي:

عقدة server.js

يعمل التطبيق على المضيف المحلي: 5000 / graphql.

يمكنك اختبار التطبيق من خلال الانتقال إلى المضيف المحلي: 5000 / graphql.

يعمل عنوان URL هذا على واجهة مستخدم Graphiql على الويب كما هو موضح في الشاشة أدناه.

يتم إعطاء الإدخال في اليسار ويظهر الإخراج في اليمين.

إعطاء المدخلات التالية

{
  مرحبا
}

هذا سيعطي الإخراج التالي

{
  "البيانات": {
    "مرحبًا": "Hello World"
  }
}

مبروك

لقد قمت بإنشاء نقطة نهاية GraphQL الأولى.

إضافة المزيد من نقاط النهاية

سننشئ نقطتين جديدتين:

  • الفيلم: ستُرجع نقطة النهاية هذه فيلمًا ، نظرًا لمعرف الفيلم
  • المخرج: ستعيد نقطة النهاية هذه مديرًا لهوية المخرج. سيعود أيضًا جميع الأفلام التي أخرجها هذا المخرج.

إضافة البيانات

عادة ، سوف يقرأ التطبيق البيانات من قاعدة البيانات. ولكن بالنسبة لهذا البرنامج التعليمي ، سنقوم بتكوين البيانات الموجودة في الكود نفسه من أجل بساطة.

قم بإنشاء ملف يسمى data.js وأضف الكود التالي.

// Hardcode بعض البيانات للأفلام والمخرجين
دع الأفلام = [{
    المعرف: 1 ،
    الاسم: "الفيلم 1" ،
    العام: 2018 ،
    مخرج: 1
}،
{
    المعرف: 2 ،
    الاسم: "الفيلم 2" ،
    السنة: 2017 ،
    مخرج: 1
}،
{
    المعرف: 3 ،
    الاسم: "الفيلم 3" ،
    السنة: 2016 ،
    مخرج: 3
}
].

السماح للمديرين = [{
    المعرف: 1 ،
    الاسم: "المخرج 1" ،
    العمر: 20
}،
{
    المعرف: 2 ،
    الاسم: "المدير 2" ،
    العمر: 30
}،
{
    المعرف: 3 ،
    الاسم: "المخرج 3" ،
    العمر: 40
}
].

الصادرات. أفلام = أفلام ؛
export.directors = المخرجون ؛

يحتوي هذا الملف على بيانات الأفلام والمخرجين. سنستخدم البيانات الموجودة في هذا الملف لنقاط النهاية.

إضافة نقطة نهاية الفيلم إلى الاستعلام

ستتم إضافة نقاط النهاية الجديدة إلى queryType في ملف query.js.

يظهر رمز نقطة نهاية الفيلم أدناه:

الفيلم:
            النوع: نوع الفيلم ،
            الحجج:
                المعرف: {type: GraphQLInt}
            }،
            حل: وظيفة (المصدر ، الحجج) {
                return _.find (movies، {id: args.id})؛
            }
        }

نوع الإرجاع لنقطة النهاية هذه هو movieType الذي سيتم تحديده قريبًا.

يتم استخدام المعلمة args للإشارة إلى الإدخال إلى نقطة نهاية الفيلم. الإدخال إلى نقطة النهاية هذه معرف من النوع GraphQLInt.

تقوم دالة التصويب بإرجاع الفيلم المقابل للمعرّف ، من قائمة الأفلام. find هي وظيفة من مكتبة lodash تستخدم لإيجاد عنصر في القائمة.

يظهر الرمز الكامل لـ query.js أدناه:

const {GraphQLObjectType ،
    GraphQLString،
    GraphQLInt
} = require ('graphql') ؛
const _ = require ('lodash') ؛

const {movieType} = require ('./ types.js') ؛
دع {movies} = يتطلب ('./ data.js') ؛


/ / حدد الاستعلام
const queryType = جديد GraphQLObjectType ({
    الاسم: "الاستعلام" ،
    مجالات: {
        مرحبا: {
            النوع: GraphQLString ،

            حل: وظيفة () {
                عودة "مرحبا العالم" ؛
            }
        }،

        الفيلم:
            النوع: نوع الفيلم ،
            الحجج:
                المعرف: {type: GraphQLInt}
            }،
            حل: وظيفة (المصدر ، الحجج) {
                return _.find (movies، {id: args.id})؛
            }
        }
    }
})؛

export.queryType = queryType؛

من التعليمات البرمجية أعلاه ، يمكننا أن نرى أن movieType محدد فعليًا في types.js.

إضافة نوع الفيلم المخصص

قم بإنشاء ملف يسمى types.js.

أضف الكود التالي في types.js

مقدار ثابت {
    GraphQLObjectType،
    GraphQLID،
    GraphQLString،
    GraphQLInt
} = require ('graphql') ؛

/ / حدد نوع الفيلم
movieType = جديد GraphQLObjectType ({
    الاسم: فيلم
    مجالات: {
        المعرف: {type: GraphQLID} ،
        الاسم: {النوع: GraphQLString} ،
        السنة: {type: GraphQLInt}،
        DirectorId: {type: GraphQLID}

    }
})؛

export.movieType = movieType؛

يمكن ملاحظة أن movieType يتم إنشاؤه كـ GraphQLObjectType.

لديها 4 حقول: معرف ، اسم ، سنة ومخرج. يتم تحديد أنواع كل حقل من هذه الحقول أيضًا أثناء إضافتها.

هذه الحقول تأتي مباشرة من البيانات. في هذه الحالة ، سيكون من قائمة الأفلام.

إضافة الاستعلام واكتب لنقطة نهاية المخرج

مثل الفيلم ، يمكن إضافة نقطة النهاية للمخرج.

في query.js ، يمكن إضافة نقطة نهاية المخرج كما يلي:

مدير: {
            نوع: نوع المخرج ،
            الحجج:
                المعرف: {type: GraphQLInt}
            }،
            حل: وظيفة (المصدر ، الحجج) {
                return _.find (مخرجين ، {id: args.id}) ؛
            }
        }

يمكن إضافة نوع الإخراج على النحو التالي في types.js:

// تعريف مدير النوع
directorType = جديد GraphQLObjectType ({
    الاسم: "المدير" ،
    مجالات: {
        المعرف: {type: GraphQLID} ،
        الاسم: {النوع: GraphQLString} ،
        العمر: {النوع: GraphQLInt} ،
        الأفلام: {
            النوع: قائمة GraphQLList الجديدة (movieType) ،
            حل (المصدر ، الحجج) {
                return _.filter (movies، {directorId: source.id})؛
            }

        }

    }
})؛

انتظر دقيقة. نوع الإخراج مختلف قليلاً عن نوع الفيلم. لماذا هذا؟

لماذا هناك وظيفة العزم داخل directorType؟ سبق أن رأينا أن وظائف الحل كانت موجودة فقط في الاستعلام ...

الطبيعة الخاصة للمخرج

عند استدعاء نقطة نهاية المخرج ، يتعين علينا إعادة تفاصيل المخرج ، وكذلك جميع الأفلام التي أخرجها المخرج.

معرِّف الحقول الثلاثة الأولى والاسم والعمر في DirectorType واضحة ومباشرة وتأتي مباشرة من البيانات (قائمة المديرين).

يحتاج الحقل الرابع ، الأفلام ، إلى احتواء قائمة الأفلام لهذا المخرج.

لهذا ، نذكر أن حقل نوع الأفلام هو قائمة GraphQLList لـ movieType (قائمة الأفلام).

لكن كيف سنجد بالضبط كل الأفلام التي أخرجها هذا المخرج؟

لهذا ، لدينا وظيفة العزم داخل حقل الأفلام. المدخلات إلى وظيفة الحل هذه هي المصدر والحجج.

مصدر سيكون تفاصيل الكائن الأصل.

دعنا نقول أن معرف الحقول = 1 ، الاسم = "عشوائي" والعمر = 20 للمخرج. ثم source.id = 1 ، source.name = "عشوائي" و source.age = 20

لذلك في هذا المثال ، تكتشف وظيفة العزم كل الأفلام التي يتطابق المخرج فيها مع معرف المخرج المطلوب.

الشفرة

يتوفر رمز كامل لهذا التطبيق في هذا GitHub repo

اختبار التطبيق

الآن ، دعونا نختبر التطبيق لسيناريوهات مختلفة.

قم بتشغيل التطبيق باستخدام عقدة server.js.

انتقل إلى المضيف المحلي: 5000 / graphql وجرب المدخلات التالية.

فيلم

إدخال:

{
  فيلم (المعرف: 1) {
    اسم
  }
}

انتاج:

{
  "البيانات": {
    "فيلم": {
      "الاسم": "الفيلم 1"
    }
  }
}

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

في الفيلم (المعرف: 1) ، المعرف هو معلمة الإدخال. نطلب من الخادم إعادة إرسال الفيلم الذي يحمل معرف 1.

إدخال:

{
  فيلم (المعرف: 3) {
    اسم
    هوية شخصية
    عام
  }
}

انتاج:

{
  "البيانات": {
    "فيلم": {
      "الاسم": "الفيلم 3" ،
      "المعرف": "3" ،
      "السنة": 2016
    }
  }
}

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

مدير

إدخال:

{
  المخرج (المعرف: 1) {
    اسم
    هوية شخصية،
    عمر
  }
}

انتاج:

{
  "البيانات": {
    "مدير": {
      "الاسم": "المخرج 1" ،
      "المعرف": "1" ،
      "العمر": 20
    }
  }
}

إدخال:

{
  المخرج (المعرف: 1) {
    اسم
    هوية شخصية،
    عمر،
    أفلام{
      اسم،
      عام
    }
  }
}

انتاج:

{
  "البيانات": {
    "مدير": {
      "الاسم": "المخرج 1" ،
      "المعرف": "1" ،
      "العمر": 20 ،
      "أفلام": [
        {
          "الاسم": "الفيلم 1" ،
          "السنة": 2018
        }،
        {
          "الاسم": "الفيلم 2" ،
          "السنة": 2017
        }
      ]
    }
  }
}

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

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

مبروك

أنت تعرف الآن المفاهيم الأساسية لـ GraphQL.

يمكنك التحقق من الوثائق لمعرفة المزيد عن GraphQL

عن المؤلف

أحب التكنولوجيا ومتابعة التطورات في هذا المجال. أود أيضًا مساعدة الآخرين في معرفتي التكنولوجية.

لا تتردد في الاتصال معي على حسابي على LinkedIn https://www.linkedin.com/in/aditya1811/

يمكنك أيضا متابعة لي على تويتر https://twitter.com/adityasridhar18

موقع الويب الخاص بي: https://adityasridhar.com/

نشرت أصلا في adityasridhar.com.