"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > إصدار API في Monite

إصدار API في Monite

تم النشر بتاريخ 2024-11-08
تصفح:256

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

في تطوير واجهة برمجة تطبيقات الويب، أنت دائمًا معرض لخطر كسر كود المستخدمين مع كل تحديث جديد. إذا كان منتجك عبارة عن واجهة برمجة التطبيقات (API)، فستكون هذه التحديثات مرعبة في كل مرة. منتجات Monite الرئيسية هي واجهة برمجة التطبيقات (API) الخاصة بنا وSDK ذات العلامة البيضاء. نحن شركة تعطي الأولوية لواجهة برمجة التطبيقات (API) لذا فإننا نحرص بشدة على الحفاظ على استقرار واجهة برمجة التطبيقات (API) الخاصة بنا وسهولة استخدامها. ومن ثم فإن مشكلة كسر التغييرات تقع بالقرب من أعلى قائمة أولوياتنا.

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

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

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

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

احذر من السعر

إصدار واجهة برمجة التطبيقات (API) صعب جدًا. بساطته الوهمية تتلاشى بسرعة بمجرد البدء في تنفيذها. للأسف، الإنترنت لا يحذرك أبدًا نظرًا لوجود عدد قليل جدًا من الموارد حول هذا الموضوع. تتجادل الغالبية العظمى منهم حول مكان وضع إصدار واجهة برمجة التطبيقات (API) ولكن عددًا قليلًا فقط من المقالات النادرة تحاول الإجابة: "كيف يمكننا تنفيذه ؟". وأكثرها شيوعاً هي:

  • وضع إصدارات مختلفة من نفس تطبيق الويب في عمليات نشر منفصلة
  • نسخ المسارات الفردية التي تغيرت بين الإصدارات
  • نسخ التطبيق الذي تم إصداره بالكامل لكل إصدار

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

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

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

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

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

كيف يمكننا تنفيذ إصدار API؟

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

  1. "من السهل الحفاظ على عدد كبير من الإصدارات" للتأكد من أن الإصدار لا يؤدي إلى إبطاء تطوير الميزات لدينا
  2. "حذف الإصدارات القديمة أمر سهل" للتأكد من أنه يمكننا تنظيف قاعدة التعليمات البرمجية الخاصة بنا دون بذل أي جهد
  3. "إنشاء إصدارات جديدة ليس بالأمر السهل جدًا" للتأكد من استمرار تحفيز المطورين لدينا لمحاولة حل المشكلات بدون إصدارات.
  4. "من السهل الحفاظ على سجل التغيير بين الإصدارات" للتأكد من أننا وعملائنا يمكننا دائمًا التأكد من الاختلافات الحقيقية بين الإصدارات

للأسف، لم يكن هناك سوى القليل من البدائل لأساليبنا الحالية. وهنا خطرت ببالي فكرة مجنونة: ماذا لو حاولنا بناء شيء متطور، شيء مثالي للمهمة - شيء مثل إصدار Stripe's API؟

نتيجة لعدد لا يحصى من التجارب، أصبح لدينا الآن Cadwyn: إطار عمل إصدار واجهة برمجة التطبيقات (API) مفتوح المصدر الذي لا ينفذ نهج Stripe فحسب، بل يبني عليه بشكل كبير. سنتحدث عن تنفيذ Fastapi وPydantic ولكن المبادئ الأساسية هي اللغة والإطار الحيادي.

كيف يعمل كادوين

تغييرات الإصدار

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

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

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

class ChangeUserAddressToAList(VersionChange):
    description = (
        "Renamed `User.address` to `User.addresses` and "
        "changed its type to an array of strings"
    )
    instructions_to_migrate_to_previous_version = (
        schema(User).field("addresses").didnt_exist,
        schema(User).field("address").existed_as(type=str),
    )

    @convert_request_to_next_version_for(UserCreateRequest)
    def change_address_to_multiple_items(request):
        request.body["addresses"] = [request.body.pop("address")]

    @convert_response_to_previous_version_for(UserResource)
    def change_addresses_to_single_item(response):
        response.body["address"] = response.body.pop("addresses")[0]

يتم استخدام الإرشادات_to_migrate_to_previous_version بواسطة Cadwyn لإنشاء تعليمات برمجية لإصدارات API الأقدم من المخططات، كما أن وظيفتي المحول هما الخدعة التي تسمح لنا بالحفاظ على أي عدد نرغب فيه من الإصدارات. تبدو العملية كما يلي:

  1. يقوم Cadwyn بتحويل كافة طلبات المستخدمين من إصدارات واجهة برمجة التطبيقات الأقدم إلى أحدث إصدار من واجهة برمجة التطبيقات باستخدام محول Change_address_to_multiple_items، وتوجيهها إلى منطق أعمالنا
  2. يتم دائمًا تصميم منطق الأعمال واستجابات واجهة برمجة التطبيقات (API) ونماذج قاعدة البيانات وفقًا لأحدث إصدار من واجهة برمجة التطبيقات (بالطبع، يجب أن يظل يدعم الميزات القديمة حتى لو تم إسقاطها في الإصدارات الجديدة)
  3. بعد أن ينتج منطق الأعمال الاستجابة، يقوم Cadwyn بتحويلها إلى إصدار API الأقدم الذي يستخدمه طالب العميل حاليًا باستخدام محول Change_addresses_to_single_item.

بعد أن يقوم مشرفو API لدينا بإنشاء تغيير الإصدار، يجب عليهم إضافته إلى VersionBundle الخاص بنا لإخبار Cadwyn أنه سيتم تضمين VersionChange هذا في بعض الإصدارات:

VersionBundle(
    Version(
        date(2023, 4, 27),
        ChangeUserAddressToAList
    ),
    Version(
        date(2023, 4, 12),
        CollapseUserAvatarInfoIntoAnID,
        MakeUserSurnameRequired,
    ),
    Version(date(2023, 3, 15)),
)

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

تسلسل الإصدار

تعتمد تغييرات الإصدار على الواجهة العامة لواجهة برمجة التطبيقات (API) ولا نقوم تقريبًا بإضافة تغييرات جذرية إلى إصدارات واجهة برمجة التطبيقات (API) الحالية. وهذا يعني أنه بمجرد إصدار النسخة – فلن يتم كسرها.

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

API Versioning at Monite

تأثيرات جانبية

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

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


فئة RequireCompanyAttachedForPayment(VersionChangeWithSideEffects): الوصف = ( "يجب أن يكون لدى المستخدم الآن رقم تعريف الشركة في حسابه" "إذا كانوا يريدون إجراء دفعات جديدة" )
class RequireCompanyAttachedForPayment(VersionChangeWithSideEffects):
    description = (
        "User must now have a company_id in their account "
        "if they want to make new payments"
    )
سيسمح أيضًا لمشرفي واجهة برمجة التطبيقات (API) بالتحقق من أن طلب العميل يستخدم إصدار واجهة برمجة التطبيقات (API) الذي يتضمن هذا التأثير الجانبي:


إذا تم تطبيق RequireCompanyToBeAttachedForPayment.is: validate_company_id_is_attached(المستخدم)
class RequireCompanyAttachedForPayment(VersionChangeWithSideEffects):
    description = (
        "User must now have a company_id in their account "
        "if they want to make new payments"
    )
لا الرصاص الفضي

يتمتع Cadwyn بالعديد من الفوائد: فهو يقلل بشكل كبير من العبء الواقع على المطورين لدينا ويمكن دمجه في بنيتنا التحتية لإنشاء سجل التغيير تلقائيًا وتحسين مستندات واجهة برمجة التطبيقات (API) الخاصة بنا.

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

شكر خاص لـ Brandur Leach على مقالته حول إصدارات API في Stripe وعلى المساعدة التي قدمها لي عندما قمت بتنفيذ Cadwyn: لم يكن الأمر ممكنًا بدون مساعدته.

بيان الافراج تم نشر هذه المقالة على: https://dev.to/monite/api-versioning-at-monite-3ba3?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3