طراحی API (رابط برنامهنویسی کاربردی — Application Programming Interface) وقتی درست انجام شود، سالها بیسروصدا کار میکند؛ وقتی نادرست انجام شود، هر تغییر کوچک به یک بحران تبدیل میشود. در سبک REST، بخش بزرگی از این بحرانها ریشه در یک تصمیم دیرهنگام دارند: نسخهبندی. اگر قرارداد API را طوری بچینید که دیرتر بشکند، نسخهبندی از یک درد همیشگی به ابزاری نادر تبدیل میشود.
نسخهبندی بیمهٔ رایگان نیست
خیلی از تیمها نسخهبندی را مثل بیمه میبینند: «معلوم نیست لازم شود، ولی میگذاریمش». مشکل این است که هر نسخهٔ فعال، هزینهٔ جاری دارد:
- منطق برنامه دو شاخه میشود و هر باگ باید دو بار بررسی شود.
- مستندات، تستها و نمونهکدها دو برابر میشوند.
- مصرفکنندههای قدیمی مهاجرت نمیکنند و شما سالها با آنها میمانید.
- هر قابلیت جدید باید در چند نسخه پاسخ درست بدهد.
پس هدف درست این نیست که «چطور نسخهبندی را پیاده کنیم»، بلکه این است که «چطور طراحی کنیم که نسخهبندی دیر و کم لازم شود».
اصول REST که عمر قرارداد را طولانی میکنند
بیشتر شکستنهای قرارداد، از نقض اصول پایه میآید، نه از پیچیدگی موضوع:
- منبعمحور باشیم، نه عملمحور. آدرسها باید اسم باشند (/orders) و رفتار با فعل مشخص شود، نه با آدرسهایی مثل /getOrdersNow که با هر نیاز جدید تغییر میکنند.
- معنای افعال را جدی بگیریم. درخواستهای خواندنی نباید اثر جانبی داشته باشند و عملیات تکراری باید نتیجهٔ یکسان بدهند؛ این تفکیک، نیمی از انتظارهای مصرفکننده را تثبیت میکند. افعال و کدهای وضعیت استاندارد HTTP برای همین کار تعریف شدهاند.
- کد وضعیت را درست بهکار ببریم. اگر خطای اعتبارسنجی را با کد موفقیت برگردانید، مصرفکننده مجبور میشود بدنهٔ پاسخ را حدس بزند و هر تغییر متن خطا برایش شکننده میشود.
- بدنهٔ پاسخ را باز بگذاریم. افزودن فیلد جدید یک تغییر سازگار است؛ به شرطی که از ابتدا به مصرفکننده بگویید فیلدهای ناشناخته را نادیده بگیرد.
- خطا را ساختارمند برگردانیم. یک قالب ثابت با کد خطای ماشینخوان و پیام انسانی، جلوی وابستگی مصرفکننده به متن پیام را میگیرد.
- مجموعهها را قابل صفحهبندی و فیلتر کنیم. اگر «همهچیز در یک پاسخ» باشد، اولین برخورد با حجم داده، شما را مجبور به تغییر ساختار میکند.
سه نوع تغییر، سه واکنش متفاوت
قبل از تصمیم دربارهٔ نسخه جدید، تغییر را دستهبندی کنید. بیشتر تیمها این کار را نمیکنند و برای تغییرات بیخطر هم نسخهٔ جدید میسازند.
- تغییر افزایشی: افزودن فیلد اختیاری، افزودن یک آدرس جدید، افزودن پارامتر فیلتر. هیچ نسخهٔ جدیدی لازم نیست.
- تغییر رفتاری: تغییر مقدار پیشفرض، سختتر شدن اعتبارسنجی، تغییر معنای یک فیلد موجود. مرزی است؛ اگر تعداد مصرفکنندههای وابسته کم است، با اطلاعرسانی و بازهٔ گذار حل میشود. اگر زیاد است، نسخهٔ جدید بدهی کمهزینهتر است.
- تغییر شکننده: حذف یا تغییرنام فیلد، تغییر نوع داده، عوض شدن معنا. اینجا نسخهٔ جدید یا مسیر جدید واقعاً لازم است.
الگوهای نسخهبندی و انتخاب آگاهانه
- در مسیر آدرس مثل /v2/orders: ساده، در لاگ و مرورگر دیده میشود و کش را راحت میکند؛ اما نسخه را به هویت منبع میچسباند و همهٔ آدرسها را همزمان جابهجا میکند.
- در پارامتر کوئری مثل ?version=2: سبک و کمدردسر برای شروع، اما در مسیرهای تودرتو و کش دشوار میشود و راحت فراموش میشود.
- در هدر یا نوع رسانه مثل Accept: application/vnd.company.v2+json: از نظر معماری خالصتر و آدرسها تمیز میمانند؛ اما تست دستی، مرورگر و ابزارهای ساده با آن سختتر کار میکنند.
کدام را انتخاب کنیم
اگر API عمومی و مصرفکنندههایتان متنوعاند، نسخهبندی در مسیر آدرس کمریسکترین انتخاب است: واضح، قابل مشاهده و کمدردسر در پشتیبانی. اگر API داخلی است و مصرفکنندهها را میشناسید و میتوانید هماهنگ کنید، سادهترین راه این است که اصلاً نسخه نگذارید و بهجایش سیاست «فقط تغییرات افزایشی» را اجرا کنید. انتخاب میانه، نسخهبندی در هدر است؛ وقتی آدرسهای تمیز برایتان ارزش محصولی دارد.
قواعد عملی برای دیر رسیدن نسخهبندی
- قرارداد را ماشینخوان توصیف کنید و همان توصیف را منبع مستندات و تست قرار دهید.
- فیلد را هرگز یکباره حذف نکنید؛ اول منسوخ اعلام کنید، سپس در نسخهٔ بعدی بردارید.
- برای هر مقدار شمارشی، مسیر «ناشناخته» بگذارید تا افزودن مقدار جدید کسی را نشکند.
- قبل از هر تغییر، فهرست مصرفکنندههای واقعی و وابستگیهایشان را بهروز نگه دارید.
- احراز هویت و مجوزدهی را در لایهٔ API حل کنید، نه در کلاینت؛ مرز اعتماد در امنیت برنامههای وب همانجایی است که تصمیمهای نسخهبندی هم باید گرفته شوند.
- برای نسخهٔ قدیمی سیاست منسوخی روشن بگذارید: اعلام، بازهٔ گذار، سپس خاموشی.
جمعبندی
نسخهبندی ابزار مدیریت بحران است، نه بخشی از زیباییشناسی معماری. اگر منبعمحور طراحی کنید، معنای افعال و کدهای وضعیت را رعایت کنید، خطاها را ساختارمند بدهید و سیاست «فقط تغییرات افزایشی» را جدی بگیرید، سالها بدون نسخهٔ جدید کارتان راه میافتد. اما وقتی تغییر شکننده ناگزیر شد، بین مسیر، پارامتر و هدر یکی را آگاهانه انتخاب کنید و هزینهٔ نگهداری آن را از همان روز اول بپذیرید.