إخلاء المسؤولية: نحن لا نصف بالتفصيل "الجوهر السحري" وتاريخ أصل الآلة (لقد قيل الكثير بالفعل حول هذا الأمر). نأمل أن يستفيد من هم على دراية بـ GraphQL من خبرتنا العملية.
لقد شاركنا مؤخرًا في إنشاء كتالوج إنترنت لمعدات الإضاءة. لإنشاء صفحات إعلانية ، يمكن لمسؤولي الموقع استخدام المصمم: حدد الكتل الضرورية (على سبيل المثال ، اللافتات أو القوائم) ، وقم بملئها بالبيانات ، وتحديد ترتيب العرض والإعدادات الأخرى. في نفس الوقت ، قدم التطبيق مكونات تم وضعها مسبقًا لكل نوع كتلة.
في كل فئة من فئات الكتالوج عبر الإنترنت ، تم عرض بطاقات لمجموعات منتجات مختلفة ، وعندما تمرر الماوس فوق البطاقة ، تم عرض قائمة بخصائص المنتجات المرفقة.
احتجنا إلى عرض خصائص المنتجات في هيكل شجرة وتوفير سرعة عالية بما فيه الكفاية لمعالجة الطلبات.
لقد اخترنا ترتيب العمل التالي مع الطلبات:
- اطلب كل مجموعات المنتجات لفئة معينة (عادة حوالي 50 مجموعة).
- اطلب قائمة المنتجات لكل مجموعة.
- اطلب قائمة خصائص لكل منتج.
نظرًا لأننا كنا نطور تطبيقًا يعتمد على GraphQL ، فقد كنا مستعدين لحقيقة أن بعض البيانات سيكون لها بنية متداخلة معقدة نوعًا ما. على الرغم من أن تفريع هذه البنية كان منطقيًا لتطوير الواجهة الخلفية ، إلا أنه يجب كتابة بعض المنطق "الإضافي" في المقدمة لمعالجة البيانات وإخراجها إلى المكون ، وفقًا للتصميم.
نظرًا لخصائص مُنشئ GraphQL ، فقد قررنا جمع الخصائص والقيم الفريدة ليس في الخلف ، ولكن في المقدمة ، ثم عرضها بترتيب معين. ومع ذلك ، كانت معالجة الطلب بطيئة للغاية - ما يصل إلى 20 ثانية ، وهو ما لم يناسبنا بالطبع.
لهذا السبب ، بدأنا في تقسيم كل طلب إلى استعلامات فرعية صغيرة وتحميل البيانات في أجزاء. نتيجة لذلك ، تم تحسين سرعة التطبيق بشكل ملحوظ - لم تستغرق الطلبات أكثر من ثانيتين. على الرغم من زيادة عدد الطلبات ، فقد انخفض الحمل على النظام واختفت الحاجة إلى تحميل البيانات غير المستخدمة.
بعد ذلك ، لنتحدث بمزيد من التفاصيل حول العمل مع GraphQL.
ميزات العمل مع GraphQL
كانت متطلبات المنتج بالنسبة لنا هي استخدام لغة استعلام GraphQL التي طورها Facebook. لهذا السبب ، لم ننغمس في الحجج التي لا نهاية لها حول أيهما أفضل ، GraphQL أم REST - بدلاً من ذلك ، قررنا استخدام التكنولوجيا الصحيحة بالطريقة الأكثر فاعلية ، مع مراعاة جميع نقاط قوتها.
لقد أخذنا في الاعتبار أن GraphQL قد تم تصميمها لتبسيط تطوير وصيانة واجهات برمجة التطبيقات ، وذلك بشكل أساسي من خلال وجود نقطة نهاية واحدة.
GET /news
GET /posts
POST /news
POST /post
لدى GraphQL نقطة نهاية واحدة. هذا يعني أننا لسنا بحاجة إلى تقديم طلبين منفصلين للحصول على بيانات من مصدرين مختلفين. تدمج GraphQL جميع الطلبات والطفرات في نقطة نهاية واحدة وتجعلها متاحة للرجوع إليها ، فضلاً عن تجنب الإصدار المتأصل في واجهات برمجة تطبيقات REST.
توفر GraphQL القدرة على تحسين الأداء والحصول على البيانات المطلوبة بالضبط في الوقت الحالي باستخدام صيغة استعلام خاصة: يجب إدراج الحقول المطلوبة في الاستعلام.
const FETCH_USER_DATA = gql`
query FetchUserData {
user {
firstName
lastName
date
}
}
`;
تستخدم GraphQL كيانات مكتوبة بقوة ونوع مخطط ، والذي بدوره يكون مفيدًا بالتزامن مع TypeScript وإنشاء نوع الواجهة الأمامية.
يمكن بالتأكيد تنفيذ العديد من هذه الميزات على واجهات برمجة تطبيقات REST ، ومع ذلك ، توفرها GraphQL خارج الصندوق.
لتفاعل العميل مع GraphQL ، اخترنا الحل الأكثر شيوعًا مع التوثيق الجيد - مكتبة Apollo Client ، والتي تتيح لك الحصول على بيانات التطبيق وتخزينها مؤقتًا وتعديلها. يمنحك عميل Apollo القدرة على استخدام أدوات وأدوات الطلب والطفرات لتتبع حالة التنزيل / الخطأ بسهولة.
في المقدمة أيضًا ، استخدمنا إطار عمل NextJS ، الذي تم اختياره مع مراعاة العوامل التالية: العرض المسبق (يوفر NextJS آلية بسيطة جدًا لتنفيذ الإنشاء الثابت و SSR خارج الصندوق) ، ودعم جميع حلول css-in-js الحالية ، والتوجيه الديناميكي ، ودعم الملفات الثابتة (مثل الصور) في مكونات React.
أخيرًا ، بمجرد اختيار التقنيات ، دعنا ننتقل إلى التطوير. للوهلة الأولى ، يبدو كل شيء جيدًا: المكتبات الحديثة ، التوثيق الجيد ، العديد من حالات الاستخدام المختلفة. تم تصميم كل تقنية على حدة لتسهيل التطوير المريح والسريع. من خلال إنشاء نموذج أساسي ، والذي كان لا غنى عنه ، وتصميم مكونات واجهة المستخدم ، اقتربنا تدريجياً من مرحلة التفاعل الفعال بين مكتباتنا. هنا بدأ كل المرح.
بالنظر بشكل أعمق إلى آليات NextJS ، نرى أنه يستخدم شكلين من أشكال العرض المسبق: التوليد الثابت و SSR. يتم تنفيذ كلتا الاستراتيجيتين باستخدام وظائف التحميل المسبق للبيانات الخاصة:
`getInitialProps` (SSR) - عند التحميل لأول مرة ، يتم تشغيله على الخادم ، ويطلب البيانات ثم يمررها إلى المكون على شكل دعائم.
function Component ({data}) {
...
}
Component.getInitialProps = async (ctx) => {
const res = await fetch('https://...')
const json = await res.json()
return { data: json.data }
}
"getStaticProps" (الجيل الثابت) - يعمل في مرحلة البناء. يعرض NextJS الصفحة مسبقًا باستخدام الخاصيات التي تم إرجاعها من هذه الوظيفة.
export async function getStaticProps(context) {
return {
props: {}, // props
}
}
`getServerSideProps` (عرض جانب الخادم) - يعرض NextJS الصفحة مسبقًا عند كل طلب ، باستخدام البيانات التي يتم إرجاعها من هذه الوظيفة كعناصر.
export async function getServerSideProps(context) {
return {
props: {}, // props
}
}
وبالتالي ، يتم الإعلان عن جميع الوظائف المدرجة خارج المكون ، وتتلقى بعض البيانات وتمريرها إلى المكون. يؤدي هذا إلى إحدى مشكلات التفاعل مع عميل Apollo. توفر المكتبة آليات الاستعلام مثل الخطاف ʻuseQuery` ومكوِّن `Query` ، ولا يمكن استخدام أي من الطرق المقترحة خارج المكون. مع وضع ذلك في الاعتبار ، قررنا في مشروعنا استخدام مكتبة next-with-apollo وفي النهاية شعرنا بالرضا عن النتيجة.
مشكلة أخرى معروفة في Apollo Client ، والتي واجهناها أيضًا ، هي إمكانية وجود حلقة لا نهائية من الطلبات من الخطاف ʻuseQuery`. جوهر المشكلة هو أن عميل Apollo يستمر في إرسال الطلبات إلى أجل غير مسمى حتى يتلقى البيانات بنجاح. يمكن أن يؤدي هذا إلى موقف حيث "يتوقف" المكون في طلب لانهائي ، إذا لم يتمكن الخادم من إرجاع البيانات لسبب ما.
في حالتنا ، كان أحد الأسباب هو التغيير في المخطط في الخلف. ينشئ Apollo الأنواع من تلقاء نفسه ، لذلك عند كتابة الاستعلامات في المقدمة ، كان علينا اتباع الأنواع التي تم إنشاؤها لتجنب الأخطاء. على سبيل المثال ، كان لدينا طلب عمل ، دون أي مشاكل في النوع. ومع ذلك ، عند تغيير المخطط على الواجهة الخلفية ، تتغير الأنواع في نفس الوقت ، مما قد يتسبب في توقف الاستعلام العامل عن العمل. بالنظر إلى ذلك ، من الأفضل تنفيذ التسجيل على الفور ونظام واضح للتعامل مع الأخطاء من أجل إنقاذ أعصاب الفريق ووقته.
في رأينا ، اتضح أنه من المفيد جدًا في استعلامات الرسم البياني أنه يمكنك تحديد البيانات التي يجب تلقيها بالضبط. عند إرسال عدد كبير من الطلبات ، يؤدي ذلك إلى تجنب معالجة البيانات غير الضرورية. في المقابل ، يمكن أن يؤثر هذا بشكل كبير على الأداء مع زيادة كمية البيانات.
من الجدير بالذكر أن إحدى مزايا GraphQL هي ملاءمة التطوير ودعم واجهة برمجة التطبيقات ، ولكن هذه الخاصية أكثر أهمية لتطوير الواجهة الخلفية ، ووفقًا لملاحظاتنا ، ليس لها تأثير كبير على المقدمة. نظرًا لتوليد الأنواع ، في كل مرة يتم فيها تغيير المخطط على اللوحة المعززة ، نعيد كتابة جميع الاستعلامات المتأثرة. كان على بيك أيضًا تحسين المخطط إذا احتجنا إلى الحصول على شيء في المقدمة لم يتم تنفيذه بعد. في الوقت نفسه ، أتاح إنشاء الأنواع عند استخدام TypeScript اكتشاف العديد من الأخطاء في مرحلة كتابة الكود.
تلخيص لما سبق
وفقًا لملاحظاتنا ، تُستخدم GraphQL على نطاق واسع في أنواع مختلفة من حلول تكنولوجيا المعلومات وتوفر مزايا معينة لفريق التطوير. دعنا نلخص الميزات الرئيسية لـ GraphQL التي واجهناها أثناء تطوير المشروع:
- . graphql , TypeScript .
- . GraphQL - . , ( , ). graphql «» ,
- . graphql- , . .
- . GraphQL , .
! , .