پرش به مطلب اصلی

فراخوانی یک سرویس بیرونی از دل یک اسکریپت

هدف​

کاری کنید یک اسکریپت سمت سرور چیزی بیرون از پلتفرم را فراخوانی کند — پرداختی را بگیرد، به سامانه‌ای دیگر بگوید رکوردی تغییر کرده، یا برای کسی ایمیل بفرستد — و نشانی‌ای که فراخوانی می‌شود تنظیمی باشد در دست مدیر، نه سطری در اسکریپت شما.

دو تابع​

هر دو در گام افزونهٔ سرور و در API سفارشی در دسترس‌اند.

var answer = callService('par_payment_service', '{"reference":"ORD-1","amount":25}');

var sent = sendEmail('par_mail_service', { to: 'buyer@example.test', subject: 'Your order is paid', body: 'Thank you.' });

بدنه می‌تواند متن باشد، مانند بالا، یا یک شیء یا فهرست که به‌صورت JSON فرستاده می‌شود: callService('par_payment_service', { reference: 'ORD-1', amount: 25 }) همان چیز را می‌فرستد.

پاسخ callService یک شیء است:

ویژگیچیست
statusوضعیت HTTP که سرویس پاسخ داده است
okبرای ۲۰۰ تا ۲۹۹ برابر true است، تا حالت رایج یک ویژگی باشد نه یک محاسبه
bodyآنچه پاسخ داده، به شکل متن
truncatedاگر پاسخ بزرگ‌تر از آن بوده که کامل خوانده شود، true است

آرگومان نخست نام سرویس است، نه نشانی​

این همان بخشی است که تازه‌کارها را غافلگیر می‌کند، و تمام طراحی همین است.

'par_payment_service' نام منطقی یک متغیر محیط است. شما آن را در راهکار خود اعلام می‌کنید و یک مدیر مقدارش — یعنی نقطهٔ پایانی — را در هر محیط تعیین می‌کند. بنابراین:

  • اسکریپت شما می‌گوید چه چیزی را فرا می‌خواند، هرگز نمی‌گوید کجا؛
  • محیط توسعه به یک نمونهٔ آزمایشی اشاره می‌کند و محیط عملیاتی به درگاه واقعی، بدون هیچ تغییری در راهکار؛
  • محیطی که چیزی برایش تنظیم نشده باشد، به هیچ‌جا نمی‌رسد.

عمداً هیچ تابعی وجود ندارد که یک نشانی اینترنتی بگیرد. چنین تابعی به هر اسکریپتی در هر مستأجری اجازه می‌داد به هر جایی اتصال باز کند، و هیچ اندازه بازبینی راهکارها پس از آن، این را جبران نمی‌کرد.

راه‌اندازی​

۱. سرویس را اعلام کنید. در مرکز کنترل مدیریت، متغیرهای محیط را باز کنید و یکی بسازید — par_payment_service از نوع متن. توضیحی بنویسید که کارش چیست؛ کسی که آن را در محیط عملیاتی تنظیم می‌کند ممکن است شما نباشید. ۲. آن را به راهکار خود بیفزایید تا همراه آن سفر کند. اعلام یک متغیر سفر می‌کند؛ مقدارش نه — و همین است که تنظیمات محیط توسعه را از محیط عملیاتی دور نگه می‌دارد. ۳. مقدار را در این محیط تنظیم کنید — نقطهٔ پایانی، یک نشانی مطلق http:// یا https://. ۴. گام را بنویسید. در گام افزونه یا API سفارشی خود، callService را با همان نام صدا بزنید.

از کدام سوی ذخیره‌سازی فراخوانی کنیم​

یک گام افزونهٔ سرور یا پیش از نوشته‌شدن رکورد اجرا می‌شود یا پس از آن، و فراخوانی‌های بیرونی بسته به ماهیتشان به سوی متفاوتی تعلق دارند:

فراخوانیمرحلهچرا
گرفتن پرداخت، رزرو موجودی در سامانه‌ای دیگرPreOperationدرون تراکنش ذخیره‌سازی رخ می‌دهد، پس اگر رکورد سپس ذخیره نشود، چیزی باقی نمی‌ماند که ادعا کند پولی گرفته شده است
فرستادن تأییدیه، آگاه‌کردن سامانه‌ای دیگرPostOperationرکورد تا آن لحظه وجود دارد، پس از کار افتادن سرویس ایمیل پیامی را به تعویق می‌اندازد نه اینکه رکورد را برگرداند

فراخوانی پیش از ذخیره ده ثانیه فرصت دارد. در این مدت ذخیره‌سازی را باز نگه داشته و کسی به یک چرخندهٔ انتظار نگاه می‌کند. اگر سرویسی که فرا می‌خوانید بیش از این نیاز دارد، گام را ناهمگام کنید — آنگاه پس از ذخیره و مستقل اجرا می‌شود و هر قدر لازم باشد وقت دارد.

چه چیزی شکست به شمار می‌آید​

این تمایز ارزش یک بار آموختن را دارد، چون تعیین می‌کند چه مقدار از اسکریپت را باید بنویسید:

  • وضعیتی که خود سرویس برگزیده، یک پاسخ است. 402 از یک درگاه پرداخت یعنی کارت رد شده — پیشامدی عادی که شما دربارهٔ آن تصمیم می‌گیرید. اسکریپت آن را در answer.status می‌گیرد و ادامه می‌دهد.
  • هیچ پاسخی نداشتن یک شکست است و خودش گام را متوقف می‌کند: چنین سرویسی وجود ندارد، در این محیط نقطهٔ پایانی تنظیم نشده، نقطهٔ پایانی یک نشانی وب نیست، یا سرویس هرگز پاسخ نداد. اسکریپت دربارهٔ هیچ‌یک از اینها کاری نمی‌تواند بکند، و ادامه‌دادن یعنی چنان رفتار کردن که گویی یکپارچه‌سازی انجام شده است.

پس شکل بیشتر گام‌ها چنین است:

var answer = callService('par_payment_service', body);
if (answer.ok) {
setValue('par_payment_reference', answer.body);
} else {
throwValidationError(`The payment service refused this order (${answer.status}).`);
}

فرستادن ایمیل​

sendEmail نام سرویس و یک پیام را می‌گیرد و پیام را به آن سرویس می‌فرستد. پیام از آنِ پلتفرم است، پس یک استقرار یک وفق‌دهندهٔ ایمیل را پیکربندی می‌کند نه یکی به ازای هر اسکریپتی که پیامی می‌فرستد.

در پیامچیست
toگیرنده. یک نشانی، چند نشانی جداشده با ویرگول یا نقطه‌ویرگول، یا یک فهرست
ccرونوشت، به همان شکل. اختیاری
replyToپاسخ به کجا برود، تا مشتری به نویسنده پاسخ دهد نه به نشانی بی‌پاسخ. اختیاری
subjectموضوع
bodyمتن پیام
htmlاگر متن HTML است true. اختیاری؛ در غیر این صورت متن ساده

sendEmail هرگز اسکریپت شما را متوقف نمی‌کند. پاسخش { ok, error } است. وقتی ایمیل نرفت، چون اینجا سرویس ایمیلی تنظیم نشده، نشانی پذیرفته نشد یا سرویس ایمیل در دسترس نبود، ok برابر false است و error دلیلش را می‌گوید، با واژه‌هایی که نشان می‌دهند چه کسی می‌تواند درستش کند. این به اسکریپت امکان می‌دهد شکست را ثبت کند و بعداً دوباره بفرستد، که فروش پارس‌ور ایمیل را همین‌طور ناموفق علامت می‌زند. اگر ذخیره باید به‌جایش متوقف شود، این را بگویید:

if (!sent.ok) { throwValidationError(sent.error); }

اسکریپتی که پیش از این نوشته شده چهار آرگومان می‌داد (sendEmail(service, to, subject, body)). باید به شکل پیامِ بالا درآید.

پلتفرم SMTP صحبت نمی‌کند. به هر چه محیط نام ببرد ارسال می‌کند، که هر ارائه‌دهندهٔ ایمیلی آن را دارد؛ استقراری که تنها راهش یک بازپخش SMTP است، یک نقطهٔ پایانی کوچک HTTP جلوی آن می‌گذارد.

امتحان کنید​

راهکار نمونهٔ business-rules-outbound-calls را وارد کنید. یک جدول سفارش دارد، دو سرویس که به شکل متغیر محیط اعلام شده‌اند و چیزی برایشان تنظیم نشده، و دو گام — یکی که پیش از ذخیره پرداخت را می‌گیرد و یکی که پس از آن تأییدیه را ایمیل می‌کند. فایل README آن گام‌به‌گام نشان می‌دهد چگونه سرویس‌ها را به نقطه‌ای که 200 پاسخ می‌دهد و سپس به نقطه‌ای که 402 پاسخ می‌دهد وصل کنید و ببینید ذخیره‌سازی رد می‌شود بی‌آنکه چیزی ذخیره شود.

همچنین ببینید​