طراحی لایهٔ استعلام قبض سه اپراتور موبایل با یک نگاشت
برای پشتیبانی از همراه اول، ایرانسل و رایتل یک نوع داده، یک جدول slug و یک آداپتور کافی است؛ فراخوان موازی سه اپراتور پیشفرض خوبی نیست.
اگر محصول شما قبض موبایل را برای هر سه اپراتور پشتیبانی میکند، فقط یک نگاشت پاسخ بنویسید و سه آدرس. کد شما نباید سه شاخهٔ جدا داشته باشد؛ شاخهٔ دوم و سوم همان کپی اولی است و یک روز یکیشان را فراموش میکنید.
این مقاله دربارهٔ ساختار کد است، نه دربارهٔ اینکه قبض چیست. فرض میکنیم شما میخواهید استعلام قبض رایتل را کنار همراه اول و ایرانسل در یک ماژول بگذارید و میپرسید مرز کجاست.
چرا یک نگاشت کافی است
پاسخ سه سرویس همان شکل را دارد: بلوک final_term و بلوک mid_term، و در هرکدام amount، bill_id و payment_id. تفاوت فقط در نشانی فراخوان است: bill-mci، bill-irancell و bill-rightel.
پس نیازی نیست سه نوع داده تعریف کنید. یک نوع بنویسید و اپراتور را مثل یک برچسب کنارش بگذارید.
```ts type Operator = 'mci' | 'irancell' | 'rightel';
interface TermBill { amount: number; billId: string; paymentId: string; }
interface MobileBill { operator: Operator; finalTerm: TermBill; midTerm: TermBill; fetchedAt: string; }
const SLUG: Record<Operator, string> = { mci: 'bill-mci', irancell: 'bill-irancell', rightel: 'bill-rightel', }; ```
تابع فراخوان هم یک ورودی بیشتر از شماره نمیخواهد: اپراتور. بقیه مشترک است.
واحد مبلغ را جایی ثابت کنید
پیش از اینکه عدد amount را به رابط بدهید، واحدش را از مستندات سرویس یا با یک خط آزمایشی روشن کنید و در یک تابع تبدیل ثابتش نگه دارید. این کار را درست پیش از اولین نمایش مبلغ انجام دهید، نه بعد از شکایت کاربر. اشتباه دهبرابری در واحد پول از آن اشتباههایی است که تا کسی صورتحساب را کنار هم نگذارد دیده نمیشود.
تصمیم اصلی: اپراتور از کجا بیاید
سه راه دارید و هرکدام هزینهای:
| راه | خوب است برای | ضعف |
|---|---|---|
| تشخیص از پیششماره | بیشتر شمارهها | شمارهٔ منتقلشده را غلط میخواند |
| پرسیدن از کاربر | وقتی دقت مهم است | یک مرحله بیشتر |
| فراخوان موازی هر سه | هیچوقت پیشفرض نباشد | سه برابر هزینه، دو پاسخ بینتیجه |
من ترکیب اول و دوم را انتخاب میکنم: پیششماره حدس اول است و اگر نتیجه نیامد، کاربر اپراتور را انتخاب میکند. جدول پیششماره را از منبعی که خودتان به آن اعتماد دارید بسازید و نسخهدار نگه دارید، چون با گذر زمان تغییر میکند. در این مقاله عمداً بازهای ننوشتهام.
فراخوان موازی سه اپراتور وسوسهانگیز است چون ساده است. اما حساب کنید: برای هر کاربر یک پاسخ مفید و دو فراخوان بینتیجه. بینتیجه بودن هم یعنی not_found یا پاسخ منفی که طبق مستندات ممکن است حساب شوند. این را در مقالهٔ خطاها و هزینهٔ ایرانسل با جزئیات آوردهام.
مسیر بازگشتی برای شمارهٔ ناشناخته
در رابط کاربری، دو حالت را جدا کنید:
- شمارهٔ شناختهشده: خودکار فراخوان بزنید و فقط اگر نتیجه نیامد پیام بدهید «اپراتور شما را درست تشخیص ندادیم؟».
- شمارهٔ ناشناخته: بدون فراخوان، یک انتخابگر سهگزینهای نشان بدهید.
اولی تجربهٔ روان میدهد و دومی جلوی هزینهٔ بیهوده را میگیرد. بعد از اینکه کاربر اپراتور را انتخاب کرد، آن را کنار شمارهٔ ذخیرهشدهاش نگه دارید تا بار دوم نپرسید.
یک آداپتور، نه سه مسیر
آداپتور باید این کارها را انجام دهد و هیچ کار دیگری نکند:
- شماره را یکدست کند.
- اپراتور را به slug برگرداند.
- پاسخ را به
MobileBillتبدیل کند. - کدهای خطا را به همان چهار رفتار تبدیل کند: موفق، بدون رکورد، قابلتکرار، غیرقابلتکرار.
منطق نمایش و پرداخت بیرون از آداپتور بماند. اگر روزی اپراتور چهارمی اضافه شد، فقط یک مقدار به Operator و یک سطر به جدول slug اضافه میشود.
آزمون: سه شماره، سه خروجی
برای آزمون، از هر اپراتور یک خط آزمایشی بردارید و این موارد را بسنجید:
- پاسخ هر سه به یک
MobileBillمیرسد. - خط اعتباری هر اپراتور به شاخهٔ «بدون رکورد» میرود، نه به خطا.
- شمارهٔ نامعتبر، پیش از هر فراخوانی، رد میشود. چنین ورودی طبق مستندات رایگان است ولی بیدلیل بار شبکه میسازد.
- پاسخ ۴۲۹ باعث تلاش مجدد با فاصله میشود.
آنچه این رویکرد حل نمیکند
- تفاوت رفتار اپراتورها در زمان بهروزشدن رکورد را از بین نمیبرد. شکل داده یکی است، سرعت ثبت پرداخت ممکن است نباشد.
- خط اعتباری را قبضدار نمیکند.
- پرداخت را انجام نمیدهد؛ فقط شناسهها را تحویل درگاه شما میدهد.
- شمارهٔ منتقلشده را بهطور خودکار پیدا نمیکند. فقط مسیر بازگشتی برای آن میگذارد.
خطای شبکه و زمان انتظار
سه اپراتور یک آدرس پایه و یک روش احراز دارند، پس تنظیم زمان انتظار هم یکی است. یک سقف مشخص بگذارید و بعد از آن خطا را به رفتار «قابلتکرار» ببرید. تکرار را روی همان اپراتور انجام دهید، نه روی اپراتور دیگر. تغییر اپراتور هنگام خطای شبکه فقط پاسخ بیربط میسازد.
چه چیزی را کش کنید
نتیجهٔ استعلام قبض با گذشت زمان کهنه میشود، چون میاندوره هر روز عوض میشود. اگر خودتان کش میسازید، مدتش را کوتاه نگه دارید و زمان fetchedAt را کنار مبلغ به کاربر نشان دهید. در پاسخ API هم فیلد source.cached و source.stale میگویند آیا پاسخ تازه است یا نه؛ آنها را به لایهٔ نمایش برسانید تا کاربر بداند عدد برای کی است.
یک ویژگی که ارزش افزودن دارد
وقتی ساختار یکسان شد، ویژگیهای جدید تقریباً رایگان میشوند: یک صفحهٔ «همهٔ خطوط من» که چند شماره را از اپراتورهای مختلف یکجا نشان میدهد، یا یادآور مهلت بر اساس finalTerm برای هر سه. چنین چیزی با سه شاخهٔ جدا سه برابر کد میخواست.
ساختار پوشهها در پروژه
یک ساختار ساده کافی است: پوشهای برای قبوض موبایل با یک فایل نوعها، یک فایل جدول اپراتور و slug، یک فایل آداپتور و یک فایل آزمون. فایل رابط کاربری بیرون از این پوشه بماند و فقط MobileBill را بشناسد. وقتی بعداً قبض تلفن ثابت را هم اضافه کردید، میتوانید همین الگو را با دو بلوک مشابه تکرار کنید؛ فقط ورودی عوض میشود. به این ترتیب کد شما برای هر سرویس تازه الگوی آماده دارد.
اگر عجله دارید
یک نوع داده، یک جدول slug، یک آداپتور و یک مسیر بازگشتی برای اپراتور نامعلوم. فراخوان موازی هر سه را پیشفرض نکنید. اگر جای شما بودم، اول آداپتور را با همراه اول مینوشتم، سپس سطرهای ایرانسل و رایتل را اضافه میکردم و آزمون سهشماره را همان روز مینوشتم. برای رایتل فقط یک سطر در جدول slug لازم است (API قبض رایتل). شکل دقیق فراخوان در مستندات API آمده است.
وبسرویس مرتبط با این راهنما
API استعلام قبض رایتل
صورتحساب خط دائمی رایتل.
راهنماهای مرتبط
پرسش و تجربه کاربران
اگر این راهنما جوابتان را نداد، همینجا بپرسید. پرسشها را تیمملی ایپیآی پاسخ میدهد و هر نظر پیش از انتشار بررسی میشود.
هنوز پرسشی ثبت نشده، اولین نفر باشید.
