API Versioning

من خودم چندین سال هستش که دارم برنامه نویسی میکنم و توی این چند سال بار ها و بار ها پیش اومده که برای بعضی پروژه ها نیاز بوده تا Api بدم, خیلی وقت ها پیش میاد که این Api مربوط میشه به یه اپ موبایلی, توی نسخه های اولیه که شما Api رو آماده میکنین همیشه بعضی قسمت ها هستش که نادیده گرفته میشه و دلایل خاص خودش رو داره(ممکنه به خاطر عدم پشتیبانی اون قسمت توی اپلیکیشن باشه یا به خاطر درخواست مدیرتون که میخواد محصول سریعتر وارد بازار بشه) چیزی که مشخص هستش اینه که این محصول وارد بازار میشه و ممکنه نسخه اولیه محصول موبایلی شما تعداد زیادی دانلود بگیره و بعد از مدت کوتاهی مجبور بشین که یه سری متد جدید به Api هاتون اضافه کنین و یا توی پارامتر های بازگشتی خودتون تغییری بدین تا با نسخه های جدیدتر اپلیکیشن سازگار باشه و همین نقطه آغاز شروع مشکل میشه.

و اما چه مشکلی؟ اگر رابط کاربری شما تغییر کنه و فیلد هایی بهش اضافه بشه و یا فیلد هایی کم بشه و یا اگر برنامه نویس موبایل شما با استفاده از Reflection سعی کرده باشه تا دیتایی رو که دریافت میکنه تبدیل به مدل های مورد استفاده خودش بکنه در این صورت هر تغییری در Api باعث از کار افتادن نسخه های قبلی تر اپلیکیشن شما میشه, ولی خب راهکار چیه؟ نمیتونیم که منتظر معجزه بمونیم که همون لحظه که Api جدید و نسخه جدید رو گذاشتیم بالا همه سریع به روز رسانی کنن(ممکنه کسی که از Api شما استفاده میکنه چندین سازمان یا شرکت مختلف باشن و صرفا یه موبایل اپلیکیشن نباشه!) یا ممکن هستش که شما تغییری توی پارامتر های ورودی Api ها داده باشین و مقادیر ارسالی به سمت متد های شما باعث بروز خطا بشه

روشی که برای این منظور پیشنهاد شده به روش زیر هستش:

فرض کنید ما یه سرویسی نوشتیم که به صورت Rest Api کار میکنه و قراره یک آی دی بگیره و اطلاعات کاربر رو برگردونه, توی نسخه اول دو فیلد نام و نام خانوادگی رو برمیگردونیم, و در نسخه دوم یک فیلد تصویر هم به اون اضافه کردیم اما در نسخه سوم نام و نام خانوادگی رو ترکیب کردیم و به جای برگردوندن آدرس تصویر که در نسخه دوم داشتیم این بار میخوام محتوای تصویر رو به صورت Base64 برگردونیم؛ به این منظور ما برای هر تغییر جدیدی که میدیم باید یک ورژن جدید ایجاد کنیم:

http://virgool.io/api/customers/1234
http://virgool.io/api/v2.0/customers/1234
http://virgool.io/api/v3.0/customers/1234

این روش باز خودش مشکل آفرین میشه چرا که نیاز داره تا ما هم به مشتری ها همواره اعلام کنیم نسخه جدید ایجاد شده نسخه های قدیمی تر نگه داری بشن و ....

یکی از روش هایی که خودم بعد مطالعه در موردش واقعا بهش علاقه مند شدم و به نظرم به اندازه کافی هوشمندانه هستش راهکاری هستش که تلگرام برای نسخه بندی Api های خودش در نظر گرفته هستش.

برای این کار تلگرام اومد و یک استاندارد به اسم Tl-Schema تعریف کرد, که همه تعاریف متد هاشو برد داخل این Schema, و در مرحله بعدی اومد مفهومی به اسم SupportedLayer و SecretSupportedLayer رو به Api خودش اضافه کرد, به این صورت که مقادیری که داخل این فیلد ها ارسال میشه باعث میشه تا Api متوجه بشه که قراره از کدوم Schema استفاده کنه.

در این مطلب قصد ندارم وارد جزئیات عملکردی MTProto بشم به خاطر همین سعی میکنم خیلی خلاصه توضیح بدم, کاری که تلگرام انجام داده به شکل زیر هستش که شما میای یک سری اعداد هگز رو به عنوان اسم متد بهش ارسال میکنی( به عنوان مثال 0x8c718e87 به معنی پیغام هستش)

messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
---functions---
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;

حالا وقتی که میخوایم Api رو صدا بزنیم مقدار مربوط به SupportedLayer در بخشی از این پیامی که داریم به سمت سرور ارسال میکنیم قرار میگیره, با این روش دیگه نیازی نیست که بخوایم دامنه های مختلف برای Api در نظر بگیریم چه اپلیکیشن و یا چه سازمانی بخواد از نسخه Api استفاده کنه فقط در صورتی که خودش به نسخه جدید به روزرسانی کرده باشه با تغییر این مقدار به آخرین عددی که ما به عنوان آخرین لایه معرفی کردیم میتونه با نسخه به روز شده کار کنه