یک توسعهدهنده دو هفته را صرف جایگزینی یک REST API با tRPC در یک ابزار داخلی کرد.
چرا این تغییر اهمیت داشت
پشته (stack) قدیمی ما را مجبور میکرد تا یک DTO، یک validator و مجموعهای جداگانه از تایپهای TypeScript را برای فرانتاند نگهداری کنیم. اگر نام یک فیلد در بکاند را تغییر میدادیم، API همچنان کد ۲۰۰ را برمیگرداند، رابط کاربری (UI) به رندر شدن ادامه میداد و باگ تنها به صورت مقادیر "undefined" ظاهر میشد. یک مشتری قبل از اعضای تیم متوجه مشکل شد. قراردادهای REST مشکل را پنهان میکردند و فایلهای اضافی باعث نگهداری (maintenance) اضافهای میشدند که هرگز ارزش خود را نشان ندادند.
ساختار REST چگونه بود
- OpenAPI spec – یک فایل استاتیک که endpointها را توصیف میکرد اما هرگز به عنوان مرجع اصلی (source of truth) عمل نمیکرد.
- Client SDK generation step – یک مرحله در CI که یک wrapper جاوااسکریپتی تولید میکرد.
- Postman collection – یک فایل تست مشترک که هیچکس از آن استفاده نمیکرد.
- Manual TypeScript interfaces – تایپهای دستی که باید با سرور همگام (sync) میماندند.
هر تغییر در API حداقل سه مورد از این موارد، به علاوه validator و هرگونه فراخوانی fetch در مراحل بعدی را تحت تأثیر قرار میداد. این فرآیند مستعد خطا و کند بود.
چگونه tRPC حجم کدها را کاهش داد
tRPC فایل قرارداد جداگانه را حذف میکند. سرور یک router type را صادر (export) میکند و کلاینت همان تایپ را وارد (import) میکند. اگر نام یک فیلد در بکاند را تغییر دهید، ادیتور بلافاصله عدم تطابق را نشان میدهد؛ بدون نیاز به اجرای کد یا ارسال درخواست ناموفق. توسعهدهنده موارد زیر را حذف کرد:
- فایل OpenAPI spec.
- مرحله Client SDK generation.
- Postman collection بلااستفاده.
- پوشه Manual TypeScript interfaces.
مخزن (repo) سبکتر شد و بازخوردها به جای پس از استقرار (deployment)، در حین توسعه دریافت میشدند.
محدودیتهای tRPC
tRPC تنها زمانی کار میکند که هر دو طرف از TypeScript استفاده کنند. در موارد زیر کارایی ندارد:
- تیم موبایل از Swift یا Kotlin استفاده کند.
- API باید توسط شرکای خارجی مصرف شود.
- به یک رابط عمومی و مستقل از زبان (language-agnostic) نیاز داشته باشید.
مهاجرت در واقع به چه چیزهایی نیاز داشت
تلاش دو هفتهای چیزی فراتر از کپی-پیست کردن بود. توسعهدهنده مجبور بود:
- تمام فراخوانیهای
fetchرا برای استفاده از توابع کلاینت tRPC بازنویسی کند. - منطق مدیریت خطا (error-handling) را تنظیم کند.
- کامپوننتهای UI را که به وضعیتهای loading و retry وابسته به پاسخهای خام HTTP بودند، بهروزرسانی کند.
سوالاتی که باید قبل از شروع بپرسید
- آیا هم فرانتاند و هم بکاند از TypeScript استفاده میکنند؟ بدون یک سیستم تایپ مشترک، tRPC مزیت اصلی خود را از دست میدهد.
- آیا یک تیم مسئول هر دو طرف است؟ شکاف در مالکیت میتواند دوباره باعث ناهماهنگی در قراردادها (contract drift) شود.
- آیا در حال رفع یک باگ مشخص هستید یا صرفاً به دنبال یک ترند هستید؟ افزایش بهرهوری واقعی است، اما باید یک چالش موجود را حل کند.
یک رویکرد ترکیبی برای سال ۲۰۲۵
بسیاری از تیمها با اجرای هر دو پشته، نقطه بهینه را پیدا میکنند:
- tRPC برای لایههای اپلیکیشن داخلی، جایی که کدها کاملاً TypeScript هستند و یک تیم واحد مالک سرور و کلاینت است.
- REST برای وبهوکها، APIهای عمومی و یکپارچهسازی با شرکا، جایی که دسترسی مستقل از زبان مورد نیاز است.
استفاده از ابزار مناسب برای هر سطح، سرعت توسعه داخلی را حفظ میکند و در عین حال، باز بودن مورد نیاز برای مصرفکنندگان خارجی را نیز تضمین مینماید.
نتیجهگیری: جایگزینی REST با tRPC میتواند آرتیفکتهای تکراری قرارداد را حذف کرده و باگها را در زمان ویرایش کد آشکار کند، اما این مزایا تنها زمانی محقق میشوند که کل پشته از TypeScript استفاده کند و تیم بتواند هزینه مهاجرت را بپذیرد. یک استراتژی ترکیبی به شما اجازه میدهد بدون محدود کردن مصرفکنندگان غیر TypeScript، از مزایای آن بهرهمند شوید.
