كتاب تمهيدي لـ GraphQL: لماذا نحتاج إلى نوع جديد من واجهة برمجة التطبيقات (الجزء 1)
نشرت: 2022-03-10في هذه السلسلة ، أود أن أقدم لكم GraphQL. في النهاية ، يجب أن تفهم ليس فقط ما هو عليه ولكن أيضًا أصوله وعيوبه وأساسيات كيفية التعامل معه. في هذه المقالة الأولى ، بدلاً من القفز إلى التنفيذ ، أريد أن أستعرض كيف ولماذا وصلنا إلى GraphQL (والأدوات المماثلة) من خلال النظر في الدروس المستفادة من آخر 60 عامًا من تطوير API ، من RPC حتى الآن. بعد كل شيء ، كما وصف مارك توين بشكل ملون ، لا توجد أفكار جديدة.
"لا يوجد شيء اسمه فكرة جديدة. إنه مستحيل. نحن ببساطة نأخذ الكثير من الأفكار القديمة ونضعها في نوع من المشكال العقلي."
- مارك توين في "السيرة الذاتية لمارك توين: الفصول من مراجعة أمريكا الشمالية"
لكن أولاً ، يجب أن أخاطب الفيل في الغرفة. الأشياء الجديدة مثيرة دائمًا ، لكنها قد تشعر أيضًا بالإرهاق. ربما تكون قد سمعت عن GraphQL وفكرت في نفسك: "لماذا ..." بدلاً من ذلك ، ربما فكرت في شيء مثل ، "لماذا أهتم باتجاه تصميم واجهة برمجة التطبيقات الجديد؟ REST ... بخير. " هذه أسئلة مشروعة ، لذا اسمحوا لي أن أشرح لماذا يجب أن تنتبه إلى هذا السؤال.
مقدمة
يجب الموازنة بين فوائد جلب أدوات جديدة لفريقك مقابل تكاليفها. هناك الكثير من الأشياء للقياس. هناك الوقت المستغرق للتعلم ، والوقت الذي يستغرقه التحويل بعيدًا عن تطوير الميزات ، والنفقات العامة للحفاظ على نظامين. مع هذه التكاليف الباهظة ، يجب أن تكون أي تقنية جديدة أفضل أو أسرع أو أكثر إنتاجية بكمية هائلة. التحسينات التدريجية ، رغم كونها مثيرة ، إلا أنها لا تستحق الاستثمار. أنواع واجهات برمجة التطبيقات التي أريد التحدث عنها ، وخاصة GraphQL ، هي في رأيي خطوة كبيرة إلى الأمام وتقدم أكثر من فائدة كافية لتبرير التكلفة.
بدلاً من استكشاف الميزات أولاً ، من المفيد وضعها في السياق وفهم كيفية ظهورها. للقيام بذلك ، سأبدأ بقليل من تلخيص تاريخ واجهات برمجة التطبيقات.
RPC
كان RPC ، كما يمكن القول ، أول نمط رئيسي لواجهة برمجة التطبيقات وتعود أصوله إلى الحوسبة المبكرة في منتصف الستينيات. في ذلك الوقت ، كانت أجهزة الكمبيوتر لا تزال كبيرة ومكلفة للغاية لدرجة أن فكرة تطوير التطبيقات التي تعتمد على واجهة برمجة التطبيقات ، كما نفكر فيها ، كانت في الغالب مجرد نظرية. قيود مثل النطاق الترددي / زمن الوصول ، وقوة الحساب ، ووقت الحوسبة المشتركة ، والقرب المادي أجبرت المهندسين على التفكير فيما يتعلق بالأنظمة الموزعة بدلاً من الخدمات التي تعرض البيانات. من ARPANET في الستينيات ، وصولاً إلى منتصف التسعينيات مع أشياء مثل CORBA و Java's RMI ، تفاعلت معظم أجهزة الكمبيوتر مع بعضها البعض باستخدام Remote Procedure Calls (RPC) وهو نموذج تفاعل بين العميل والخادم حيث يتسبب العميل في إجراء (أو طريقة) للتنفيذ على خادم بعيد.
هناك الكثير من الأشياء الرائعة حول RPC. مبدأها الرئيسي هو السماح للمطور بالتعامل مع الكود في بيئة بعيدة كما لو كان في بيئة محلية ، وإن كان أبطأ بكثير وأقل موثوقية مما يخلق استمرارية في أنظمة مختلفة ومتباينة. مثل العديد من الأشياء التي ظهرت ARPANET ، كان هذا في وقت سابق لعصره لأن هذا النوع من الاستمرارية هو شيء ما زلنا نسعى لتحقيقه عند العمل مع إجراءات غير موثوقة وغير متزامنة مثل الوصول إلى قاعدة البيانات ومكالمات الخدمة الخارجية.
على مدى العقود ، كان هناك قدر هائل من الأبحاث حول كيفية السماح للمطورين بتضمين سلوك غير متزامن مثل هذا في التدفق النموذجي للبرنامج ؛ إذا كانت هناك أشياء مثل الوعود ، والعقود الآجلة ، والمهام المجدولة متاحة في ذلك الوقت ، فمن الممكن أن تبدو واجهة API الخاصة بنا مختلفة.
شيء رائع آخر حول RPC هو أنه نظرًا لأنه غير مقيد ببنية البيانات ، يمكن كتابة طرق متخصصة للغاية للعملاء الذين يطلبون ويستردون المعلومات المطلوبة بالضبط والتي يمكن أن تؤدي إلى الحد الأدنى من الحمل على الشبكة وحمولات أصغر.
ومع ذلك ، هناك أشياء تجعل RPC صعبًا. أولا ، الاستمرارية تتطلب السياق . ينشئ RPC ، حسب التصميم ، قدرًا كبيرًا من الاقتران بين الأنظمة المحلية والبعيدة - تفقد الحدود بين التعليمات البرمجية المحلية والبعيدة. بالنسبة لبعض المجالات ، يعد هذا أمرًا جيدًا أو حتى مفضلًا كما هو الحال في مجموعات SDK الخاصة بالعميل ، ولكن بالنسبة لواجهات برمجة التطبيقات حيث لا يتم فهم رمز العميل جيدًا ، يمكن أن يكون أقل مرونة إلى حد كبير من شيء أكثر توجهاً نحو البيانات.
الأهم من ذلك ، هو احتمال انتشار أساليب API . من الناحية النظرية ، تكشف خدمة RPC عن واجهة برمجة تطبيقات صغيرة مدروسة يمكنها التعامل مع أي مهمة. من الناحية العملية ، يمكن أن يتراكم عدد كبير من نقاط النهاية الخارجية بدون بنية كبيرة. يتطلب الأمر قدرًا هائلاً من الانضباط لمنع تداخل واجهات برمجة التطبيقات والازدواجية بمرور الوقت حيث يأتي أعضاء الفريق ويذهبون ويتحولون إلى محور المشاريع.
صحيح أنه من خلال التغييرات المناسبة في الأدوات والتوثيق ، مثل تلك التي ذكرتها ، يمكن إدارتها ، لكن في الوقت الذي كنت أكتب فيه البرامج ، صادفت عددًا قليلاً من خدمات التوثيق التلقائي والانضباط ، لذا بالنسبة لي ، هذا قليل من سمك الرنجه الاحمر.
صابون
كان نوع واجهة برمجة التطبيقات الرئيسي التالي هو SOAP ، الذي ولد في أواخر التسعينيات في Microsoft Research. SOAP ( S imple O bject A ccess P rotocol) هي مواصفات بروتوكول طموحة للاتصالات القائمة على XML بين التطبيقات. كان طموح SOAP المعلن هو معالجة بعض العيوب العملية لـ RPC ، و XML-RPC على وجه الخصوص ، من خلال إنشاء أساس جيد التنظيم لخدمات الويب المعقدة. في الواقع ، هذا يعني فقط إضافة نظام نوع سلوكي إلى XML. للأسف ، فقد خلقت عوائق أكثر مما تم حلها كما يتضح من حقيقة أن عددًا قليلاً جدًا من نقاط نهاية SOAP الجديدة تتم كتابتها اليوم.
"SOAP هو ما يعتبره معظم الناس نجاحًا معتدلًا."
- دون بوكس
كان لدى SOAP بعض الأشياء الجيدة على الرغم من الإسهاب الذي لا يطاق والأسماء الرهيبة. يمكن استخدام العقود القابلة للتنفيذ في WSDL و WADL (تُنطق "wizdle" و "waddle") بين العميل والخادم بنتائج مضمونة يمكن التنبؤ بها وآمنة من النوع ، ويمكن استخدام WSDL لإنشاء وثائق أو لإنشاء عمليات تكامل مع IDEs والأدوات الأخرى.
كان الكشف الكبير عن SOAP فيما يتعلق بتطور API هو تقديمها التدريجي وربما غير المقصود لمزيد من المكالمات الموجهة نحو الموارد. تسمح لك نقاط نهاية SOAP بطلب البيانات بهيكل محدد مسبقًا بدلاً من التفكير في الأساليب المطلوبة لإنشاء البيانات (بافتراض أنها مكتوبة بهذه الطريقة).
الجانب السلبي الأكثر أهمية لـ SOAP هو أنه مطول للغاية ؛ يكاد يكون من المستحيل استخدامه بدون الكثير من الأدوات . أنت بحاجة إلى أدوات لكتابة الاختبارات ، والأدوات لفحص الاستجابات من الخادم والأدوات لتحليل جميع البيانات. لا تزال العديد من الأنظمة القديمة تستخدم SOAP ، لكن متطلبات الأدوات تجعلها مرهقة للغاية بالنسبة لمعظم المشاريع الجديدة ، كما أن عدد وحدات البايت اللازمة لهيكل XML يجعله خيارًا سيئًا لخدمة الأجهزة المحمولة أو أنظمة الدردشة الموزعة.
لمزيد من المعلومات ، يجدر قراءة مواصفات SOAP بالإضافة إلى التاريخ المثير للدهشة لـ SOAP من Don Box ، أحد أعضاء الفريق الأصليين.
راحة
أخيرًا ، وصلنا إلى نمط تصميم API du jour: REST. تم تقديم REST في أطروحة الدكتوراه بواسطة Roy Fielding في عام 2000 ، مما أدى إلى تأرجح البندول في اتجاه مختلف تمامًا. REST هو ، من نواح كثيرة ، نقيض SOAP والنظر إليهما جنبًا إلى جنب يجعلك تشعر أن أطروحته كانت نوعًا من الإقلاع عن الغضب.
يستخدم SOAP بروتوكول HTTP كوسيلة نقل غبية ويبني هيكله في نص الطلب والاستجابة. من ناحية أخرى ، يلقي REST عقود خادم العميل ، والأدوات ، ورؤوس XML والرؤوس المفصلة ، واستبدالها بدلالات HTTP حيث إنها بنية تختار بدلاً من ذلك استخدام أفعال HTTP تتفاعل مع البيانات و URIs التي تشير إلى مورد في بعض التسلسل الهرمي بيانات.
صابون | راحة | |
---|---|---|
أفعال HTTP | الحصول عليها ووضعها ونشرها وتصحيحها وحذفها | |
تنسيق البيانات | XML | أيا كان ما تريد |
عقود العميل / الخادم | كل يوم كل يوم! | من يحتاج هؤلاء |
اكتب النظام | جافا سكريبت غير موقعة قصيرة أليس كذلك؟ | |
عناوين URL | وصف العمليات | الموارد المسماة |
يغير REST تصميم واجهة برمجة التطبيقات بشكل كامل وصريح من تفاعلات النمذجة إلى مجرد نمذجة بيانات المجال. كونك موجهًا بالكامل نحو الموارد عند العمل مع واجهة برمجة تطبيقات REST لم تعد بحاجة إلى معرفة ما يلزم لاسترداد جزء معين من البيانات أو الاهتمام به ؛ ولا يلزمك معرفة أي شيء عن تنفيذ خدمات الواجهة الخلفية.
لم تكن البساطة نعمة للمطورين فحسب ، ولكن نظرًا لأن عناوين URL تمثل معلومات مستقرة ، يمكن تخزينها مؤقتًا بسهولة ، كما أن انعدام الحالة فيها يجعل من السهل توسيع نطاقها أفقيًا ، ونظرًا لأنها تصمم البيانات بدلاً من توقع احتياجات المستهلكين ، فيمكنها تقليل مساحة سطح واجهات برمجة التطبيقات بشكل كبير .
REST رائع ، وانتشاره في كل مكان يمثل نجاحًا مذهلاً ، ولكن ، مثل جميع الحلول التي جاءت قبله ، لا يخلو REST من عيوبه. للتحدث بشكل ملموس عن بعض عيوبه ، دعنا نذهب إلى مثال أساسي. دعنا نتظاهر بأنه يتعين علينا إنشاء الصفحة المقصودة لمدونة والتي تعرض قائمة منشورات المدونة واسم مؤلفها.
لنكتب الكود الذي يمكنه استرداد بيانات الصفحة الرئيسية من واجهة برمجة تطبيقات REST العادية. سنبدأ ببعض الوظائف التي تختتم مواردنا.
const getPosts = () => fetch(`${API_ROOT}/posts`); const getPost = postId => fetch(`${API_ROOT}/posts/${postId}`); const getAuthor = authorId => fetch(`${API_ROOT}/authors/${authorId}`);
الآن ، دعنا ننسق!
const getPostWithAuthor = postId => { return getPost(postId) .then(post => getAuthor(post.author)) .then(author => { return Object.assign({}, post, { author }) }) }; const getHomePageData = () => { return getPosts() .then(postIds => { const postDetails = postIds.map(getPostWithAuthor); return Promise.all(postDetails); }) };
لذلك سوف يقوم الكود الخاص بنا بما يلي:
- إحضار كافة المشاركات ؛
- إحضار التفاصيل حول كل منشور ؛
- إحضار مصدر المؤلف لكل منشور.
الشيء الجميل هو أنه من السهل جدًا التفكير في هذا الأمر ، كما أنه منظم جيدًا ، كما أن الحدود المفاهيمية لكل مورد مرسومة جيدًا. المشكلة هنا هي أننا قدمنا للتو ثمانية طلبات للشبكة ، يحدث الكثير منها في شكل تسلسلي.
GET /posts GET /posts/234 GET /posts/456 GET /posts/17 GET /posts/156 GET /author/9 GET /author/4 GET /author/7 GET /author/2
نعم ، يمكنك انتقاد هذا المثال من خلال اقتراح أن واجهة برمجة التطبيقات يمكن أن تحتوي على نقطة نهاية مرقمة /posts
منشورات ولكن هذا يؤدي إلى تقسيم الشعر. تظل الحقيقة أنه غالبًا ما يكون لديك مجموعة من استدعاءات API لجعل ذلك يعتمد على بعضها البعض لتقديم تطبيق أو صفحة كاملة.
من المؤكد أن تطوير عملاء وخوادم REST أفضل مما جاء قبله ، أو على الأقل دليل أكثر غباءً ، لكن الكثير قد تغير في العقدين منذ ورقة Fielding. في ذلك الوقت ، كانت جميع أجهزة الكمبيوتر من البلاستيك البيج ؛ الآن هم من الألومنيوم! على محمل الجد ، كان عام 2000 بالقرب من ذروة الانفجار في الحوسبة الشخصية. كانت سرعة المعالجات تتضاعف كل عام ، وكانت الشبكات تزداد سرعة بمعدل مذهل. بلغ تغلغل الإنترنت في السوق حوالي 45٪ ولم يكن هناك مكان يذهبون إليه سوى الارتفاع.
ثم ، في حوالي عام 2008 ، أصبحت الحوسبة المتنقلة سائدة. مع الجوّال ، تراجعنا فعليًا لعقد من الزمان من حيث السرعة / الأداء بين عشية وضحاها. في عام 2017 ، لدينا ما يقرب من 80٪ من انتشار الهواتف الذكية محليًا وأكثر من 50٪ عالميًا ، وقد حان الوقت لإعادة التفكير في بعض افتراضاتنا حول تصميم واجهة برمجة التطبيقات.
نقاط ضعف REST
فيما يلي نظرة نقدية على REST من منظور مطور تطبيقات العميل ، لا سيما المطوِّر الذي يعمل في الهاتف المحمول. لا تُعد واجهات برمجة التطبيقات على غرار GraphQL و GraphQL جديدة ولا تحل المشكلات الخارجة عن متناول مطوري REST. تتمثل أهم مساهمة GraphQL في قدرتها على حل هذه المشكلات بشكل منهجي وبمستوى من التكامل لا يتوفر بسهولة في أي مكان آخر. بمعنى آخر ، إنه حل "مضمّن بالبطاريات".
نشر المؤلفون الأساسيون لـ REST ، بما في ذلك Fielding ، ورقة في أواخر عام 2017 (تأملات في النمط المعماري REST و "التصميم المبدئي لهندسة الويب الحديثة") تعكس عقدين من REST والأنماط العديدة التي ألهمتها. إنه قصير ويستحق القراءة تمامًا لأي شخص مهتم بتصميم واجهة برمجة التطبيقات.
مع بعض السياق التاريخي والتطبيق المرجعي ، دعونا نلقي نظرة على نقاط الضعف الرئيسية الثلاثة في REST.
ريست هو الشطي
تميل خدمات REST إلى أن تكون "دردشة" إلى حد ما على الأقل نظرًا لأنها تستغرق عدة رحلات ذهابًا وإيابًا بين العميل والخادم للحصول على بيانات كافية لتقديم أحد التطبيقات. سلسلة الطلبات هذه لها تأثيرات مدمرة على الأداء ، لا سيما على الهاتف المحمول. بالعودة إلى مثال المدونة ، حتى في أفضل السيناريوهات مع هاتف جديد وشبكة موثوقة مع اتصال 4G ، فقد قضيت ما يقرب من 0.5 ثانية في وقت الاستجابة قبل تنزيل البايت الأول من البيانات.
زمن انتقال 55 مللي ثانية 4G * 8 طلبات = 440 مللي ثانية زيادة
هناك مشكلة أخرى في خدمات الدردشة وهي أنه في كثير من الحالات يستغرق تنزيل طلب كبير وقتًا أقل من العديد من الطلبات الصغيرة. يعد الأداء المنخفض للطلبات الصغيرة صحيحًا لعدة أسباب بما في ذلك TCP Slow Start ، ونقص ضغط الرأس وكفاءة gzip ، وإذا كنت مهتمًا بذلك ، فإنني أوصي بشدة بقراءة شبكة متصفح Ilya Grigorik عالية الأداء. تحتوي مدونة MaxCDN أيضًا على نظرة عامة رائعة.
هذه المشكلة ليست من الناحية الفنية مع REST ولكن مع HTTP ، وتحديداً HTTP / 1. يحل HTTP / 2 مشكلة الدردشة بغض النظر عن نمط واجهة برمجة التطبيقات ، وله دعم واسع في العملاء مثل المتصفحات وحزم SDK الأصلية. لسوء الحظ ، كان الطرح بطيئًا من جانب واجهة برمجة التطبيقات. من بين أفضل 10 آلاف موقع ويب ، بلغ معدل التبني حوالي 20٪ (وهو في تزايد) اعتبارًا من أواخر عام 2017. حتى أن Node.js ، الذي أثار دهشتي كثيرًا ، حصل على دعم HTTP / 2 في إصدار 8.x. إذا كانت لديك القدرة ، يرجى تحديث بنيتك التحتية! في غضون ذلك ، دعونا لا نتوقف عن الحديث لأن هذا جزء واحد فقط من المعادلة.
بغض النظر عن HTTP ، فإن الجزء الأخير من سبب أهمية الدردشة يتعلق بكيفية عمل الأجهزة المحمولة ، وخاصة أجهزة الراديو الخاصة بها. طويل وقصير هو أن تشغيل الراديو هو أحد أكثر أجزاء الهاتف كثافة للبطارية ، لذا يقوم نظام التشغيل بإيقاف تشغيله في كل فرصة. لا يؤدي بدء تشغيل الراديو إلى استنزاف البطارية فحسب ، بل يضيف المزيد من النفقات لكل طلب.
TMI (الجلب الزائد)
المشكلة التالية مع خدمات نمط REST هي أن طريقة إرسال معلومات أكثر مما هو مطلوب. في مثال مدونتنا ، كل ما نحتاجه هو عنوان كل منشور واسم مؤلفه والذي يمثل حوالي 17٪ فقط مما تم إرجاعه. هذا هو خسارة 6x لحمولة بسيطة للغاية. في واجهة برمجة التطبيقات في العالم الحقيقي ، يمكن أن يكون هذا النوع من النفقات العامة هائلاً. مواقع التجارة الإلكترونية ، على سبيل المثال ، غالبًا ما تمثل منتجًا واحدًا مثل آلاف السطور من JSON. مثل مشكلة الدردشة ، يمكن لخدمات REST التعامل مع هذا السيناريو اليوم باستخدام "مجموعات حقول متفرقة" لتضمين أو استبعاد أجزاء من البيانات بشكل مشروط. لسوء الحظ ، يعد دعم هذا متقطعًا أو غير مكتمل أو يمثل مشكلة للتخزين المؤقت للشبكة.
الأدوات والاستبطان
آخر شيء تفتقر إليه واجهات برمجة تطبيقات REST هو آليات التأمل. بدون أي عقد مع معلومات حول أنواع الإرجاع أو بنية نقطة النهاية ، لا توجد طريقة لإنشاء وثائق بشكل موثوق أو إنشاء أدوات أو التفاعل مع البيانات. من الممكن العمل ضمن REST لحل هذه المشكلة بدرجات متفاوتة. غالبًا ما تكون المشروعات التي تنفذ OpenAPI أو OData أو JSON API بالكامل نظيفة ومحددة جيدًا ، وبدرجات متفاوتة ، موثقة جيدًا ولكن الخلفيات مثل هذه نادرة. حتى الوسائط التشعبية ، وهي ثمرة معلقة منخفضة نسبيًا ، على الرغم من الترويج لها في محادثات المؤتمر لعقود ، إلا أنها لا تعمل بشكل جيد في كثير من الأحيان ، هذا على الإطلاق.
خاتمة
كل نوع من أنواع واجهات برمجة التطبيقات معيب ، لكن كل نمط به عيوب. هذه الكتابة ليست حكمًا على الأساس الهائل الذي وضعه العمالقة في البرمجيات ، فقط لتكون تقييمًا رصينًا لكل من هذه الأنماط ، مطبقة في شكلها "الخالص" من منظور مطور العميل. آمل أنه بدلاً من الابتعاد عن هذا التفكير ، يتم كسر نمط مثل REST أو RPC ، بحيث يمكنك التخلص من التفكير في كيفية إجراء كل منهم للمفاضلات والمجالات التي قد تركز فيها المؤسسة الهندسية جهودها على تحسين واجهات برمجة التطبيقات الخاصة بها .
في المقالة التالية ، سأستكشف GraphQL وكيف تهدف إلى معالجة بعض المشكلات التي ذكرتها أعلاه. يكمن الابتكار في GraphQL والأدوات المماثلة في مستوى تكاملها وليس في تنفيذها. من فضلك ، إذا كنت أنت أو فريقك لا تبحثان عن واجهة برمجة تطبيقات "مضمنة بالبطاريات" ، ففكر في البحث عن شيء مثل مواصفات OpenAPI الجديدة التي يمكن أن تساعد في بناء أساس أقوى اليوم!
إذا كنت قد استمتعت بهذه المقالة (أو إذا كنت تكرهها) وترغب في إعطائي ملاحظات ، فيرجى العثور علي على Twitter كـebaerbaerbaer أو LinkedIn على ericjbaer.