كيفية جلب بيانات GraphQL في Next.js باستخدام Apollo GraphQL

دقائق القراءة: 8

مقدمة: دمج قوة Next.js و GraphQL

تزايد اعتماد المطورين على إطار عمل Next.js بشكل مطرد كأداة لا غنى عنها لإنشاء تطبيقات React قوية وفعالة. جزء كبير مما يجعله مميزًا هو واجهات برمجة التطبيقات المتقدمة لجلب البيانات، والتي تتيح طلب البيانات لكل صفحة على حدة بكفاءة عالية. ولكن، كيف يمكننا الاستفادة من هذه الواجهات البرمجية لتنفيذ استعلامات GraphQL لتطبيقنا؟ هذا ما سنتناوله بالتفصيل في هذا الدليل الشامل.

ما هو GraphQL؟

GraphQL هو لغة استعلامات ومحرك تشغيل يوفر طريقة مختلفة للتفاعل مع واجهات برمجة التطبيقات (APIs) مقارنة بما تتوقعه من واجهات REST API التقليدية. عند جلب البيانات، بدلاً من إجراء طلب GET إلى عنوان URL محدد للحصول على تلك البيانات، تتلقى نقاط نهاية GraphQL “استعلامًا” (query). يتكون هذا الاستعلام من تحديد دقيق للبيانات التي ترغب في الحصول عليها، سواء كانت مجموعة بيانات كاملة أو جزءًا محدودًا منها.

إذا كانت بياناتك تبدو كالتالي:

Movie {
  "title" : "Sunshine",
  "releaseYear" : "2007",
  "actors" : [...],
  "writers" : [...]
}

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

Movie {
  title
  releaseYear
}

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

ما هو Apollo GraphQL؟

Apollo GraphQL هو في جوهره تطبيق لـ GraphQL يساعد المطورين على تجميع بياناتهم كـ “رسم بياني” (graph). توفر Apollo أيضًا وتحافظ على عميل GraphQL (GraphQL client)، وهو ما سنستخدمه في هذا الدليل، والذي يسمح للمطورين بالتفاعل برمجياً مع GraphQL API. باستخدام عميل GraphQL من Apollo، سنكون قادرين على إجراء طلبات إلى GraphQL API بطريقة مشابهة لما نتوقعه من عميل طلبات يعتمد على REST.

جلب البيانات في Next.js

عند جلب البيانات باستخدام Next.js، لديك عدة خيارات لكيفية جلب تلك البيانات. أولاً، يمكنك اتباع مسار جانب العميل (client-side) وإجراء الطلب بمجرد تحميل الصفحة. المشكلة في هذا النهج هي أنك تضع العبء على العميل ليأخذ الوقت الكافي لإجراء تلك الطلبات، مما قد يؤثر على تجربة المستخدم وسرعة تحميل الصفحة.

توفر واجهات Next.js API مثل getStaticProps و getServerSideProps إمكانية جمع البيانات في أجزاء مختلفة من دورة حياة التطبيق، مما يمنحنا الفرصة لإنشاء تطبيق ثابت تمامًا (static app) أو تطبيق يتم عرضه من جانب الخادم (server-side rendered). هذه الطرق تخدم البيانات المعروضة بالفعل إلى الصفحة مباشرة إلى المتصفح، مما يحسن الأداء وتجربة المستخدم بشكل كبير. باستخدام إحدى هذه الطرق، يمكننا طلب البيانات جنبًا إلى جنب مع صفحاتنا وحقن تلك البيانات كـ props مباشرة في تطبيقنا.

ماذا سنبني؟

سنقوم بإنشاء تطبيق Next.js يعرض أحدث عمليات إطلاق الصواريخ من SpaceX. سنستخدم واجهة API التي تحتفظ بها SpaceX Land لإجراء استعلام GraphQL يجلب آخر 10 رحلات.

مثال لتطبيق Next.js يعرض آخر 10 عمليات إطلاق لـ SpaceX

باستخدام getStaticProps، سنجري هذا الطلب في وقت البناء (build time)، مما يعني أن صفحتنا سيتم عرضها بشكل ثابت مع بياناتنا، مما يضمن سرعة تحميل فائقة.

الخطوة 0: إنشاء تطبيق Next.js جديد

باستخدام Create Next App، يمكننا بسرعة إنشاء تطبيق Next.js جديد يمكننا استخدامه للبدء فورًا في كتابة الكود. داخل الطرفية (terminal)، قم بتشغيل الأمر التالي:

npx create-next-app my-spacex-launches

ملاحظة: لست مضطرًا لاستخدام my-spacex-launches، لا تتردد في استبدال ذلك بأي اسم ترغب في إعطائه للمشروع.

بعد تشغيل هذا السكريبت، سيقوم Next.js بإعداد مشروع جديد وتثبيت التبعيات. بمجرد الانتهاء، يمكنك تشغيل خادم التطوير الخاص بك:

cd my-spacex-launches
npm run dev

سيؤدي هذا إلى بدء خادم جديد على http://localhost:3000 حيث يمكنك الآن زيارة تطبيقك الجديد!

شاشة ترحيب تطبيق Next.js الجديد

الخطوة 1: إضافة Apollo GraphQL إلى تطبيق Next.js

للبدء في إجراء استعلام GraphQL، سنحتاج إلى عميل GraphQL. سنستخدم Apollo GraphQL Client لإجراء استعلاماتنا إلى خادم GraphQL الخاص بـ SpaceX. بالعودة إلى الطرفية، قم بتشغيل الأمر التالي لتثبيت تبعياتنا الجديدة:

npm install @apollo/client graphql

سيضيف هذا Apollo Client بالإضافة إلى graphql، والذي سنحتاجه لتكوين استعلام GraphQL. وبمجرد اكتمال التثبيت، سنكون جاهزين للبدء في استخدام Apollo Client.

الخطوة 2: إضافة البيانات إلى صفحة Next.js باستخدام getStaticProps

قبل جلب أي بيانات باستخدام Apollo، سنقوم بإعداد صفحتنا لتكون قادرة على طلب البيانات ثم تمرير تلك البيانات كـ prop إلى صفحتنا في وقت البناء. لنقم بتعريف دالة جديدة في أسفل الصفحة أسفل مكون Home تسمى getStaticProps:

export async function getStaticProps() {
  // الكود سيتم وضعه هنا
}

عندما يقوم Next.js ببناء تطبيقنا، فإنه يعلم أن يبحث عن هذه الدالة. لذا، عندما نقوم بتصديرها، فإننا نخبر Next.js أننا نريد تشغيل كود في تلك الدالة. داخل دالة getStaticProps الخاصة بنا، سنقوم في النهاية بإرجاع props إلى الصفحة. لاختبار ذلك، لنضف ما يلي إلى دالتنا:

export async function getStaticProps() {
  return {
    props: {
      launches: []
    }
  }
}

هنا، نقوم بتمرير prop جديد باسم launches وتعيينه إلى مصفوفة فارغة. الآن، بالعودة إلى مكون Home الخاص بنا، لنضف وسيطًا جديدًا مفككًا (destructured argument) سيعمل كـ prop خاص بنا جنبًا إلى جنب مع عبارة console.log لاختبار prop الجديد:

export default function Home({ launches }) {
  console.log('launches', launches);
  // ... بقية المكون
}

إذا قمنا بإعادة تحميل الصفحة، يمكننا أن نرى أننا نقوم الآن بتسجيل prop الجديد launches والذي يتضمن مصفوفة فارغة تمامًا كما عرفنا.

إخراج console.log يعرض مصفوفة launches فارغة

الشيء الرائع في هذا هو أنه نظرًا لأن دالة getStaticProps التي ننشئها غير متزامنة (asynchronous)، يمكننا إجراء أي طلب نريده (بما في ذلك استعلام GraphQL) وإرجاعه كـ props إلى صفحتنا، وهو ما سنفعله بعد ذلك.

الخطوة 3: جلب البيانات باستخدام استعلام GraphQL في Next.js باستخدام Apollo Client

الآن بعد أن أصبح تطبيقنا جاهزًا لإضافة props إلى الصفحة وتم تثبيت Apollo، يمكننا أخيرًا إجراء طلب لجلب بيانات SpaceX الخاصة بنا. هنا، سنستخدم Apollo Client، والذي سيسمح لنا بالتفاعل مع خادم GraphQL الخاص بـ SpaceX. سنجري طلبنا إلى API باستخدام طريقة Next.js getStaticProps، مما يسمح لنا بإنشاء props ديناميكيًا لصفحتنا عند البناء.

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

import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

سيشمل هذا Apollo Client نفسه، و InMemoryCache الذي يسمح لـ Apollo بالتحسين عن طريق القراءة من ذاكرة التخزين المؤقت (cache)، و gql الذي سنستخدمه لتكوين استعلام GraphQL الخاص بنا.

بعد ذلك، لاستخدام Apollo Client، نحتاج إلى إعداد مثيل جديد منه. داخل الجزء العلوي من دالة getStaticProps، أضف:

const client = new ApolloClient({
  uri: 'https://api.spacex.land/graphql/',
  cache: new InMemoryCache()
});

ينشئ هذا مثيلاً جديدًا لـ Apollo Client باستخدام نقطة نهاية SpaceX API التي سنستخدمها للاستعلام. باستخدام عميلنا، يمكننا أخيرًا إجراء استعلام. أضف الكود التالي أسفل تعريف العميل:

const { data } = await client.query({
  query: gql`
    query GetLaunches {
      launchesPast(limit: 10) {
        id
        mission_name
        launch_date_local
        launch_site {
          site_name_long
        }
        links {
          article_link
          video_link
          mission_patch
        }
        rocket {
          rocket_name
        }
      }
    }
  `
});

يقوم هذا الكود بعدة أمور:

  • ينشئ استعلام GraphQL جديدًا داخل وسم gql.
  • ينشئ طلب استعلام جديد باستخدام client.query.
  • يستخدم await للتأكد من انتهاء الطلب قبل المتابعة.
  • وأخيرًا، يقوم بفك هيكلة data من النتائج، حيث يتم تخزين المعلومات التي نحتاجها.

داخل استعلام GraphQL، نخبر SpaceX API أننا نريد الحصول على launchesPast، وهي عمليات الإطلاق السابقة من SpaceX، ونريد الحصول على آخر 10 منها (باستخدام limit). داخل ذلك، نحدد البيانات التي نرغب في استعلامها.

إذا أخذنا لحظة لإضافة عبارة console.log جديدة بعد ذلك، يمكننا رؤية كيف تبدو data. بمجرد تحديث الصفحة، ستلاحظ أنك لا ترى أي شيء داخل وحدة تحكم المتصفح (browser’s console). وذلك لأن getStaticProps يعمل أثناء عملية البناء، مما يعني أنه يعمل في بيئة Node.js. لهذا السبب، يمكننا البحث داخل الطرفية الخاصة بنا ويمكننا رؤية سجلاتنا هناك:

عرض بيانات getStaticProps في الطرفية

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

return {
  props: {
    launches: data.launchesPast
  }
}

وإذا أضفنا عبارة console.log الخاصة بنا مرة أخرى إلى أعلى الصفحة لنرى كيف يبدو prop launches الخاص بنا، يمكننا أن نرى أن بيانات الإطلاق الخاصة بنا متاحة الآن كـ prop لصفحتنا:

عرض بيانات launches في وحدة تحكم المتصفح

الخطوة 4: إضافة بيانات إطلاق SpaceX إلى الصفحة

الآن الجزء المثير! لدينا بيانات الإطلاق الخاصة بنا التي تمكنا من استخدام Apollo Client لطلبها من خادم GraphQL الخاص بـ SpaceX. لقد أجرينا هذا الطلب في getStaticProps حتى نتمكن من توفير بياناتنا كـ prop launches الذي يحتوي على بيانات الإطلاق.

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

عنوان الصفحة المحدث لعرض إطلاقات SpaceX

بعد ذلك، يمكننا استخدام بطاقات الروابط الموجودة بالفعل لتضمين جميع معلومات الإطلاق الخاصة بنا. للقيام بذلك، لنضف أولاً عبارة map داخل شبكة الصفحة (page's grid)، حيث يكون المكون الذي نرجعه هو إحدى البطاقات، مع ملء تفاصيل الإطلاق:

<div className={styles.grid}>
  {launches.map(launch => {
    return (
      <a key={launch.id} href={launch.links.video_link} className={styles.card}>
        <h3>{ launch.mission_name }</h3>
        <p><strong>تاريخ الإطلاق:</strong> { new Date(launch.launch_date_local).toLocaleDateString("en-US") }</p>
      </a>
    );
  })}
</div>

يمكننا أيضًا التخلص من بقية بطاقات Next.js الافتراضية بما في ذلك Documentation و Learn.

قائمة بآخر 10 عمليات إطلاق لـ SpaceX مع التواريخ

تتضمن صفحتنا الآن آخر 10 عمليات إطلاق من SpaceX جنبًا إلى جنب مع تاريخ الإطلاق! يمكننا حتى النقر فوق أي من تلك البطاقات، ولأننا ربطنا برابط الفيديو، يمكننا الآن مشاهدة فيديو الإطلاق.

ماذا بعد؟

من هنا، يمكننا تضمين أي بيانات إضافية من داخل مصفوفة launches الخاصة بنا على صفحتنا. تتضمن واجهة API حتى صور شارات المهمة (mission patch images)، والتي يمكننا استخدامها لعرض رسومات جميلة لكل إطلاق. يمكنك حتى إضافة بيانات إضافية إلى استعلام GraphQL. يحتوي كل إطلاق على الكثير من المعلومات المتاحة بما في ذلك طاقم الإطلاق والمزيد من التفاصيل حول الصاروخ.

يمكنك استكشاف المزيد من البيانات المتاحة عبر نقطة نهاية GraphQL الخاصة بـ SpaceX على الرابط التالي: https://api.spacex.land/graphql/

الخلاصة التقنية

لقد أثبت هذا الدليل العملي فعالية دمج Next.js مع Apollo GraphQL لجلب البيانات بكفاءة عالية. من خلال الاستفادة من getStaticProps، تمكنا من إنشاء صفحات ثابتة غنية بالبيانات، مما يعزز أداء التطبيق ويحسن تجربة المستخدم بشكل ملحوظ. إن استخدام GraphQL يمنحنا مرونة لا مثيل لها في تحديد البيانات المطلوبة بدقة، بينما يوفر Apollo Client طبقة قوية وموثوقة لإدارة هذه الاستعلامات والتعامل مع ذاكرة التخزين المؤقت. هذا النهج لا يقلل فقط من حجم البيانات المنقولة، بل يفتح الباب أيضًا أمام بناء تطبيقات ويب سريعة، قابلة للتوسع، وذات كفاءة عالية في استهلاك الموارد.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *