ایک خاص قسم کی رگڑ ہے جسے ہر فلٹر ڈویلپر نے محسوس کیا ہے جس نے بیک اینڈ لکھنے کی کوشش کی ہے۔ آپ اپنے دنوں کو فرنٹ اینڈ پر اظہار خیال، null-safe، اور مضبوطی سے ٹائپ شدہ ڈارٹ کوڈ لکھتے ہوئے گزارتے ہیں۔ آپ کا ماڈل صاف ہے۔ Async/await زنجیروں کو نثر کی طرح پڑھا جاتا ہے۔ ٹائپ سسٹم کیڑے کے ٹرگر ہونے سے پہلے ان کی پوری کیٹیگریز کو پکڑ لیتا ہے۔ پھر کلاؤڈ فنکشن لکھنے کے لیے ایک نیا ٹیب کھولیں اور اچانک TypeScript فائل میں جائیں اور وہی چیز دوبارہ ڈیکلیئر کریں۔ User میں دستی طور پر دونوں ورژنوں کو ہم آہنگی میں رکھتا ہوں اور اس ماڈل کو ڈیبگ کرتا ہوں جسے میں نے ابھی ڈارٹ میں بیان کیا ہے۔ cannot read property of undefined یہ ایک غلطی ہے جسے ڈارٹ کمپائلر نے ملی سیکنڈ میں پکڑ لیا ہوگا۔
یہ رگڑ کوئی معمولی تکلیف نہیں تھی۔ یہ فلٹر ڈویلپرز کے لیے ایک بنیادی ساختی ٹیکس تھا جو پورے اسٹیک کے مالک ہونا چاہتے تھے۔ دو زبانوں میں دو کوڈ بیسز کو برقرار رکھا دو ہم آہنگی ماڈلز، دو قسم کے نظام، دو پیکیج ماحولیاتی نظام، اور دو ٹول سیٹ۔ مشترکہ ڈیٹا کی شکل میں ہر تبدیلی کے لیے دو ترمیمات کی ضرورت ہوتی ہے۔ کلائنٹ اور سرور کے درمیان ڈیٹا کے معاہدے میں کسی بھی کیڑے کو ٹریک کرنے کے لیے زبانوں کے درمیان ذہنی سیاق و سباق کی تبدیلی کی ضرورت ہوتی ہے۔ فائربیس بیک اینڈز کے ساتھ فلٹر ایپس بنانے والی ٹیمیں اکثر بیک اینڈ ڈویلپرز کی خدمات حاصل کرتی ہیں کیونکہ JavaScript کا کوگنیٹو اوور ہیڈ خاص طور پر موبائل پر مرکوز ٹیموں کے لیے بہت زیادہ تھا۔
اب یہ بدل گیا ہے۔ Cloud Functions for Firebase نے Dart کے لیے تجرباتی تعاون کا اعلان کیا ہے، ساتھ ہی ایک تجرباتی Dart Admin SDK جو آپ کو اپنے فنکشن کوڈ سے Firestore، تصدیق، کلاؤڈ اسٹوریج، اور دیگر Firebase سروسز کے ساتھ تعامل کرنے دیتا ہے۔ آپ اپنا بیک اینڈ اسی زبان میں لکھ سکتے ہیں جس میں آپ کا فرنٹ اینڈ ہے، دونوں طرف سے کھینچے گئے مشترکہ ڈارٹ پیکیج میں ڈیٹا ماڈل اور توثیق کی منطق کا اشتراک کر سکتے ہیں، اور اپنے سرور کوڈ کو اسی زبان میں تعینات کر سکتے ہیں۔ firebase یہ وہ CLI ہے جسے آپ پہلے ہی استعمال کر رہے ہیں۔ یونیفائیڈ ڈارٹ اسٹیک کا خواب جسے ڈویلپر برسوں سے مانگ رہے تھے باضابطہ طور پر پورا ہو گیا ہے۔
یہ ہینڈ بک انٹیگریشن اسٹیک کے لیے ایک مکمل انجینئرنگ گائیڈ ہے۔ ہم اس بات کا احاطہ کریں گے کہ ڈارٹ کلاؤڈ فنکشنز کیسے کام کرتے ہیں، وہ فن تعمیر اور تعیناتی میں Node.js فنکشنز سے کس طرح مختلف ہیں، ایڈمن SDK فنکشنز کو Firebase سروسز سے کیسے جوڑتا ہے، فلٹر ایپ اور بیک اینڈ کے درمیان باقاعدہ Dart پیکجز کا استعمال کرتے ہوئے منطق کا اشتراک کیسے کیا جائے، Flutter میں فنکشنز کو کال کرنے کا طریقہ، اور تمام موجودہ کام کی خصوصیات کو لوڈ کرنے سے پہلے آپ کو تجربہ کرنے کی ضرورت ہے۔ یہ 5 منٹ کا فوری آغاز نہیں ہے۔ سرورز پر ڈارٹ کا استعمال کرتے ہوئے حقیقی مصنوعات بنانے کے بارے میں فیصلہ کرنے والی ٹیموں کے لیے ایک گائیڈ۔
آخر میں، آپ مکمل اسٹیک ڈارٹ آرکیٹیکچر کو پہلے اصولوں سے سمجھیں گے، ڈارٹ کلاؤڈ فنکشنز کو ترتیب دینے، لکھنے، ان کی تقلید اور تعینات کرنے کا طریقہ جانیں گے، ایڈمن SDK کی صلاحیتوں کو سمجھیں گے، ڈیٹا ماڈل کی نقل کو ختم کرنے والے مشترکہ پیکجز بنائیں گے، اور اس بارے میں واضح فیصلے کریں گے کہ یہ تجرباتی خصوصیت پروڈکشن کے استعمال کے کیسز کے لیے کب تیار ہوگی۔
انڈیکس
شرطیں
اس ہینڈ بک کے ساتھ آگے بڑھنے سے پہلے، آپ کے پاس درج ذیل بنیادی باتیں ہونی چاہئیں: یہ گائیڈ کلاؤڈ انفراسٹرکچر کے بارے میں کسی ماہرانہ معلومات کو فرض نہیں کرتا ہے، بلکہ فلٹر اور فائر بیس کے بارے میں آپ کے علم پر مکمل طور پر بنایا گیا ہے۔
پھڑپھڑانا اور ڈارٹ کی مہارت۔ آپ کو ملٹی فائل ڈارٹ ایپلی کیشنز لکھنے میں ماہر ہونا چاہئے۔ async/await اور Futureڈارٹ کے نال سیف سسٹم اور پیکیج مینجمنٹ کو سمجھنا pub. فلٹر کلائنٹ میں اینڈ ٹو اینڈ مثالیں فنکشنز کو کال کرتی ہیں، لہذا آپ کو فلٹر ایپس بنانے میں کچھ تجربہ درکار ہوگا۔ ایک بار جب آپ اپنی فلٹر ایپ کو کسی بھی اسٹور پر بھیج دیتے ہیں، تو آپ تیار ہیں۔
فائر بیس کی بنیادی باتیں آپ کو پہلے Firebase استعمال کرنا چاہیے تھا۔ آپ نے Firebase کنسول میں ایک پروجیکٹ بنایا ہے، اسے FlutterFire CLI کا استعمال کرتے ہوئے اپنی Flutter ایپ سے منسلک کیا ہے، اور مثالی طور پر کم از کم ایک Firebase سروس استعمال کی ہے، جیسے Firestore یا Authentication۔ کلاؤڈ فنکشنز کے ساتھ کسی پیشگی تجربے کی ضرورت نہیں ہے، لیکن سرور لیس فنکشنز کے تصورات سے واقف ہونا مددگار ہے۔
کمانڈ لائن آرام۔ پورے ڈارٹ کلاؤڈ فنکشنز کا ورک فلو ٹرمینل میں ہوتا ہے۔ آپ کو کمانڈ لائن سے کمانڈ چلانے، ٹرمینل آؤٹ پٹ پڑھنے، اور فائل سسٹم کو نیویگیٹ کرنے میں ماہر ہونا چاہیے۔
اپنے بلنگ پلان سے آگاہ رہیں۔ پروڈکشن میں کسی بھی قسم کے کلاؤڈ فنکشنز کو تعینات کرنے کے لیے، آپ کے Firebase پروجیکٹ کو Blaze (Pay-as-you-go) پلان استعمال کرنا چاہیے۔ مقامی ایمولیٹرز کی Firebase فیملی آپ کو بلنگ اکاؤنٹ کے بغیر فیچرز تیار کرنے اور جانچنے دیتی ہے، تاکہ آپ اس ٹیوٹوریل کی زیادہ تر مقامی طور پر بغیر کسی قیمت کے پیروی کر سکیں۔ تاہم، ذہن میں رکھیں کہ تعیناتی کے لیے بلیز کی ضرورت ہوتی ہے۔
تیار کرنے کے اوزار۔ شروع کرنے سے پہلے، یقینی بنائیں کہ آپ کے ٹرمینل میں درج ذیل انسٹال اور قابل رسائی ہے:
-
فلٹر SDK 3.x یا اس سے زیادہ (بشمول Dart SDK 3.x)
-
Firebase CLI ورژن 15.15.0 یا اس سے زیادہ (چل رہا ہے۔
firebase --versionچیک کریں اپ ڈیٹnpm install -g firebase-tools) -
Node.js 18 یا اس سے زیادہ (Firebase CLI کے لیے درکار ہے، نہ کہ ڈارٹ کوڈ)
-
ڈارٹ پلگ ان والا کوڈ ایڈیٹر (VS کوڈ یا ڈارٹ ایکسٹینشن والا اینڈرائیڈ اسٹوڈیو)
-
Firebase کنسول میں بنایا گیا Firebase پروجیکٹ
یہ اس گائیڈ میں استعمال شدہ پیکیج ہے۔ آپ کی فنکشن ڈائرکٹری pubspec.yaml پر مشتمل ہے:
dependencies:
firebase_functions: ^0.1.0
google_cloud_firestore: ^0.1.0
firebase_functions یہ فراہم کردہ بنیادی ڈارٹ پیکیج ہے۔ fireUpرجسٹریشن API onRequest اور onCallفنکشن کوڈ میں استعمال ہونے والی ایک قسم۔ google_cloud_firestore یہ اسٹینڈ اسٹون ڈارٹ فائر اسٹور SDK ہے جو کلاؤڈ فنکشنز کے اندر صرف سرور سائیڈ پر استعمال ہوتا ہے۔ یہ موجودہ پیکیج جیسا نہیں ہے۔ cloud_firestore یہ فلٹر ایپس کے ذریعے استعمال ہونے والا ایک پیکیج ہے۔ دونوں فائر اسٹور کے ساتھ بات چیت کرتے ہیں، لیکن وہ مختلف لائبریریاں ہیں جو مختلف ماحول کے لیے ڈیزائن کی گئی ہیں۔ ایک Flutter کلائنٹ کے لیے جو Firebase کے حفاظتی اصولوں کے تحت چل رہا ہے، اور دوسرا سرور کی طرف سے مکمل ایڈمنسٹریٹر کی رسائی کے ساتھ چل رہا ہے۔
مشترکہ پیکجوں میں (اس پر مزید بعد میں) کوئی Firebase انحصار نہیں ہے۔ فلٹر ایپ pubspec.yaml ہم معیارات کا استعمال جاری رکھیں گے۔ firebase_core، cloud_firestoreاور دیگر FlutterFire پیکجز جو آپ پہلے ہی استعمال کر رہے ہیں۔
یہ اس خصوصیت کی تجرباتی حیثیت کے بارے میں اہم معلومات ہے۔ اس گائیڈ میں موجود ہر چیز Google Cloud Next 2026 میں اعلان کردہ تجرباتی ڈارٹ سپورٹ پر بنتی ہے۔ تجرباتی مطلب یہ ہے کہ API بغیر اطلاع کے تبدیل ہو سکتا ہے، Node.js فنکشنز میں دستیاب کچھ خصوصیات ابھی تک Dart میں دستیاب نہیں ہیں، اور Dart کی خصوصیات ابھی تک Firebase کنسول میں ظاہر نہیں ہوتی ہیں۔ اس کے بجائے، آپ انہیں گوگل کلاؤڈ کنسول میں کلاؤڈ رن خصوصیات والے صفحہ کے ذریعے دیکھ اور ان کا نظم کر سکتے ہیں۔ یہ واقعی نیا علاقہ ہے اور ٹیم اسے فعال طور پر تیار کر رہی ہے۔ آپ کا گائیڈ واضح طور پر تمام پابندیوں کی نشاندہی کرے گا تاکہ آپ کو ہمیشہ معلوم ہو جائے کہ حدود کہاں ہیں۔
کلاؤڈ فنکشنز کیا ہیں اور ڈارٹ سب کچھ کیوں بدل رہا ہے؟
بادل کی خصوصیات کیا ہیں؟
فائر بیس کے لیے کلاؤڈ فنکشنز ایک سرور لیس کمپیوٹنگ پلیٹ فارم ہے۔ "سرور لیس” کا مطلب ہے کہ آپ اپنے فنکشن لکھتے اور تعینات کرتے ہیں، اور Google ہر چیز کا انتظام کرتا ہے: سرورز، اسکیلنگ، لوڈ بیلنسنگ، آپریٹنگ سسٹم اپ ڈیٹس، اور دستیابی۔ آپ صرف گنتی کے وقت کے سیکنڈوں کی تعداد کے لیے ادائیگی کرتے ہیں جو آپ کا فنکشن حقیقت میں استعمال کرتا ہے، اور آپ کا فنکشن بغیر کسی انفراسٹرکچر کو ترتیب دیے بغیر خود بخود صفر سے لاکھوں درخواستوں کا پیمانہ بناتا ہے۔
قدر کی تجویز سادہ ہے۔ کلاؤڈ فنکشنز کے بغیر، فلٹر ایپ میں بیک اینڈ لاجک شامل کرنے کا مطلب ہے آپ کا اپنا سرور چلانا (منظم کرنے کے لیے مہنگا اور پیچیدہ) یا کلائنٹ میں بزنس لاجک (کم محفوظ اور اسٹور اپ ڈیٹ کے بغیر تبدیل کرنا زیادہ مشکل) ہے۔ کلاؤڈ فنکشنز ایک ہلکا پھلکا، محفوظ، اور توسیع پذیر بیک اینڈ پرت فراہم کرتے ہیں جسے آپ کی ایپ سے آزادانہ طور پر اپ ڈیٹ کیا جا سکتا ہے اور کسی بھی Firebase سروس کے ساتھ ایسی اعلیٰ اجازتوں کے ساتھ بات چیت کی جا سکتی ہے جو کلائنٹس کے پاس نہیں ہے۔
ڈارٹ سپورٹ سے پہلے، کلاؤڈ فنکشن لکھنے کے اختیارات جاوا اسکرپٹ، ٹائپ اسکرپٹ، ازگر، جاوا، گو، اور روبی تھے۔ فلٹر ڈویلپرز کے لیے، اس سب کا مطلب ڈارٹ سے سیاق و سباق کو تبدیل کرنا، ایک نئی زبان کے ماحولیاتی نظام اور ٹولز کو سیکھنا، اور کلائنٹ اور سرور کے درمیان مشترکہ منطق کو نقل کرنا ہے۔ اب جبکہ ڈارٹ اس فہرست میں شامل ہے، اور اس کے اثرات مزید گہرے ہو گئے ہیں کیونکہ فلٹر ایپس پہلے ہی ڈارٹ ہیں۔
انٹیگریشن اسٹیک: اصل میں کیا بدل رہا ہے۔
واضح تبدیلی زبان ہے۔ تم لکھو .dart اس کے بجائے فائل .ts یا .py فائل لیکن گہری تبدیلی ہے۔ کوڈ کا اشتراک کریں.
ٹائپ اسکرپٹ + فلٹر فن تعمیر میں، User ماڈل دو بار موجود ہے۔ سرور پر ٹائپ اسکرپٹ کا ایک ورژن اس بات کی وضاحت کرتا ہے کہ فائر اسٹور دستاویز کیا شکل اختیار کرتی ہے اور اس کے افعال کیا لوٹتے ہیں۔ کلائنٹ پر ڈارٹ کا ایک ورژن اس بات کی وضاحت کرتا ہے کہ فلٹر ایپ کس طرح صارف کے ڈیٹا کو پارس اور ڈسپلے کرتی ہے۔ فیلڈ تبدیل ہونے پر دونوں کو اپ ڈیٹ کریں۔ اگر ڈویلپر دونوں کو اپ ڈیٹ کرنا بھول جاتے ہیں تو کیڑے پیدا ہوتے ہیں۔ چونکہ سرورز اور کلائنٹس عام طور پر الگ الگ بنائے اور جانچے جاتے ہیں اور صرف انٹیگریشن ٹیسٹ یا پروڈکشن میں ظاہر ہوتے ہیں، ایسے کیڑے اکثر ترقی کے دوران نظر نہیں آتے۔
مکمل اسٹیک ڈارٹ فن تعمیر میں، User ماڈل ایک بار مشترکہ ڈارٹ پیکیج میں رہتا ہے جو فنکشن اور فلٹر ایپ دونوں درآمد کرتے ہیں۔ ایک جگہ تبدیلیاں کریں اور دونوں پارٹیاں فوری طور پر اپ ڈیٹس دیکھیں گی۔ ڈارٹ تجزیہ کار دونوں فریقوں کو اقسام کو صحیح طریقے سے استعمال کرنے پر مجبور کرتا ہے۔ فیلڈ کا نام تبدیل کرنا ایک ری فیکٹرنگ ہے جسے آپ ایک بار چلاتے ہیں، IDE بیک وقت پورے کوڈبیس میں نام بدلنے کا کام انجام دیتا ہے اور مرتب کرنے والا نتائج کو چیک کرتا ہے۔
یہ خاکہ کلیدی تعمیراتی اختلافات کو ظاہر کرتا ہے۔ بائیں طرف، اسٹیک کے دونوں اطراف وضاحت کرتے ہیں: User اس کا مطلب یہ ہے کہ ایک کو تبدیل کرنے سے دوسرے خود بخود تبدیل نہیں ہوتے ہیں۔ دائیں طرف دونوں طرف سے ایک سے لیا جاتا ہے۔ shared پیکج ایک ماڈل ایک بار موجود ہے۔ ڈارٹ کمپائلر بیک وقت دونوں استعمالوں کی توثیق کرتا ہے، جس سے ڈرفٹ کو احتیاط سے روکنے کی بجائے ساختی طور پر ناممکن ہو جاتا ہے۔
کیوں ڈارٹ خاص طور پر سرور لیس ماڈلز کے لیے موزوں ہے۔
ڈارٹ ایک ایڈڈ آف ٹائم (AOT) مرتب شدہ زبان ہے۔ یعنی، رن ٹائم پر ان کی تشریح نہیں کی جاتی ہے، بلکہ عمل درآمد سے پہلے مقامی بائنری کوڈ میں مرتب کیا جاتا ہے۔ یہ خاصیت سردی کے آغاز پر براہ راست اثر انداز ہوتی ہے، جو سرور کے بغیر کام کرنے والے سب سے زیادہ زیر بحث مسائل میں سے ایک ہے۔
کولڈ اسٹارٹ اس وقت ہوتا ہے جب کوئی فنکشن بیکار ہوتا ہے اور ایک نئی درخواست آتی ہے۔ پلیٹ فارم کو ایک نئی مثال دینے کی ضرورت ہے، اور اگر اس کے لیے بھاری رن ٹائم لوڈ کرنے کی ضرورت ہے (جیسے Node.js) یا ایک ورچوئل مشین (جیسے جاوا)، تو پہلی درخواست غیر فعال ہونے کے بعد کئی سیکنڈ لگ سکتی ہے۔ اس کے برعکس، ڈارٹ فنکشنز بغیر کسی رن ٹائم اوور ہیڈ کے مقامی بائنریز میں مرتب کیے جاتے ہیں۔ ڈارٹ فنکشنز کا کولڈ سٹارٹ ٹائم مساوی Node.js یا Python فنکشنز کے مقابلے میں بہت کم ہوتا ہے، جو انہیں کام کے بوجھ کے لیے بہتر بناتا ہے جہاں پہلی درخواست کی تاخیر اہم ہوتی ہے۔
تعیناتی کا عمل اس فن تعمیر کی عکاسی کرتا ہے۔ ڈارٹ فنکشن کو تعینات کرتے وقت، Firebase CLI کلاؤڈ میں مرتب کیے جانے والے سورس کوڈ کو اپ لوڈ نہیں کرتا ہے جس طرح Node.js کی تعیناتیاں کام کرتی ہیں۔ اپنی ڈویلپمنٹ مشین پر اپنے ڈارٹ کوڈ کو مقامی بائنری میں مرتب کریں، پھر اس بائنری کو براہ راست کلاؤڈ رن پر اپ لوڈ کریں۔ اس کا مطلب ہے کہ آپ کو اپنی مشین بنانے کے لیے Dart SDK کی ضرورت ہوگی (اگر آپ Flutter کے لیے تیار کر رہے ہیں، تو یہ پہلے سے شامل ہے) اور آپ جو بائنریز پروڈکشن میں چلاتے ہیں وہی وہی ہوں گی جن کا آپ نے مقامی طور پر تجربہ کیا ہے۔
مسئلہ یہ حل کرتا ہے: سرورز پر ڈارٹ سے پہلے کی زندگی
فلٹر ٹیم کی طرف سے زبان کے ٹیکس
اس خصوصیت سے پہلے، پس منظر کی خواہش رکھنے والی فلٹر ٹیموں کو ایک حقیقی تنظیمی انتخاب کا سامنا کرنا پڑا۔ آپ ایک بیک اینڈ ڈویلپر کی خدمات حاصل کر سکتے ہیں جو TypeScript یا Python جانتا ہے اور اپنے کوڈ بیس میں دو زبانوں کی مستقل تقسیم بنا سکتا ہے۔ آپ اپنے فلٹر ڈویلپر سے TypeScript یا Python سیکھنے کے لیے کہہ سکتے ہیں تاکہ پروڈکشن بیک اینڈ کوڈ لکھ سکیں۔ اس میں کافی وقت لگتا ہے اور جو لوگ بیک اینڈ لینگوئج کے ماہر نہیں ہیں بیک اینڈ کوڈ لکھنے پر مجبور کرتے ہیں۔ متبادل طور پر، ہم ایک حسب ضرورت بیک اینڈ سے مکمل طور پر گریز کر سکتے تھے اور پوری پروڈکٹ کو اس کے مطابق بنانے کی کوشش کر سکتے تھے جو Firebase کا کلائنٹ SDK براہ راست کر سکتا ہے۔ بعض اوقات اس کا مطلب کسی ایسے کلائنٹ کے پاس جانا ہوتا ہے جو کاروباری حساس منطق کو پڑھ اور ہیرا پھیری کر سکے۔
ان میں سے کوئی بھی انتخاب اچھا نہیں تھا۔ ہر ایک پروڈکٹیوٹی، کوڈ کوالٹی، یا پروڈکٹ کی سالمیت پر ٹیکس تھا اور جب تک تقسیم موجود تھی مسلسل ادا کی جاتی تھی۔
ڈیٹا معاہدہ کے مسائل
لینگویج سوئچنگ کے علاوہ، ہمیں Flutter کلائنٹ اور TypeScript بیک اینڈ کے درمیان ڈیٹا کنٹریکٹس کو دستی طور پر بھی برقرار رکھنا تھا۔ کلائنٹ اور سرور کے درمیان ہر API کال میں ڈیٹا کی کچھ شکل شامل ہوتی ہے جس پر دونوں فریقوں کو متفق ہونا ضروری ہے۔ اصل میں جو ہوا وہ مندرجہ ذیل میں سے ایک تھا: یا تو معاہدہ ایک README میں دستاویزی ہے جس کی میعاد فوری طور پر ختم ہو جاتی ہے، معاہدہ ایک مشترکہ OpenAPI یا پروٹوبف سکیما کے ذریعے نافذ کیا جاتا ہے جس میں ٹولنگ کی اہم پیچیدگی شامل ہوتی ہے، یا معاہدہ غیر رسمی ہے اور انٹیگریشن ٹیسٹنگ میں کیڑے دریافت ہوتے ہیں یا اس سے بھی بدتر، پیداوار۔
ڈارٹ ٹائپ سسٹم، جو کال کے دونوں طرف مشترک ہے، ساختی طور پر اس مسئلے کو ختم کرتا ہے۔ معاہدہ ڈارٹ قسم کا ہے۔ ڈارٹ کمپائلر یہ کام بیک وقت دونوں طرف کرتا ہے۔ برقرار رکھنے کے لیے کوئی README نہیں ہے اور بنانے کے لیے کوئی سکیما نہیں ہے۔
ٹولنگ گیپ
ڈارٹ پر کام کرنے والے فلٹر ڈویلپرز طاقتور سٹیٹک اینالائزرز، ہاٹ ری لوڈنگ، بہترین IDE ٹولز سے فائدہ اٹھاتے ہیں۔ dart fix خودکار کوڈ میں ترمیم کے لیے pub.dev کا پیکیج ایکو سسٹم سب سے عام تقاضوں کو پورا کرتا ہے۔ جب وہی ڈویلپرز اپنے بیک اینڈ کوڈ کے لیے TypeScript پر سوئچ کرتے ہیں، تو انہوں نے اپنے مانوس ٹولنگ ماحول کو پیچھے چھوڑ دیا اور ایک ایسے ماحول میں داخل ہوئے جس کے لیے ان کی اپنی کنفیگریشن، اپنا فارمیٹر، اپنا لنٹر سیٹ اپ، اور خود انحصاری کا انتظام درکار تھا۔ علمی اوور ہیڈ حقیقی تھا، اور ان ٹیموں کے لیے جہاں ہر ڈویلپر نے متعدد کردار ادا کیے تھے، یہ رگڑ کا ایک مستقل ذریعہ تھا۔
اگر آپ اپنے سرور کے لیے ڈارٹ استعمال کرتے ہیں تو یہ وہی ہے۔ dart analyze، dart formatاور dart pub کمانڈز فلٹر ایپس اور کلاؤڈ فنکشنز کوڈ دونوں میں کام کرتے ہیں۔ وہی IDE ایکسٹینشنز لاگو ہوتی ہیں۔ اسی ٹیم کے علم کا اطلاق ہوتا ہے۔
ڈارٹ کلاؤڈ کی خصوصیات کیسے کام کرتی ہیں: بنیادی فن تعمیر
انٹری پوائنٹس اور فائر اپ
کنونشن کے مطابق، تمام ڈارٹ کلاؤڈ فنکشنز ایک ہی انٹری پوائنٹ فائل سے شروع ہوتے ہیں۔ functions/bin/server.dart. کہ main فنکشن کال fireUpیہ ایک ابتدائی فنکشن ہے جو فراہم کردہ ہے۔ firebase_functions پیکج fireUp ایک HTTP سرور ترتیب دیں جو آنے والی درخواستوں کو سنتا ہے اور انہیں مناسب ہینڈلر تک پہنچاتا ہے، Google Apps کے ڈیفالٹ اسناد کا استعمال کرتے ہوئے Firebase Admin SDK کو خود بخود شروع کرتا ہے، اور درست پورٹ پر درخواستوں کو سننا شروع کر دیتا ہے۔
// functions/bin/server.dart
import 'package:firebase_functions/firebase_functions.dart';
void main(List args) async {
await fireUp(args, (firebase) {
firebase.https.onRequest(
name: 'helloWorld',
options: const HttpsOptions(cors: Cors(['*'])),
(request) async {
return Response.ok('Hello from Dart Cloud Functions!');
},
);
});
}
fireUp یہ رن ٹائم بوٹسٹریپ ہے جو . firebase_functions پیکج پہلا دعویٰ یہ ہے کہ argsکمانڈ لائن دلائل کی ایک فہرست ہے جو بائنری شروع کرتے وقت کلاؤڈ فنکشنز کا ماحول گزر جاتا ہے۔ اس میں سننے کے لیے پورٹس اور دیگر رن ٹائم کنفیگریشن شامل ہیں۔ fireUp ان دلائل کو پارس کریں اور ڈیفالٹ شیلف HTTP سرور کو کنفیگر کرنے کے لیے استعمال کریں۔ دوسری دلیل یہ ہے۔ firebase ایک ایسی چیز جو کلاؤڈ فنکشنز رن ٹائم کے ذریعہ فراہم کردہ ہر چیز کا ہینڈل ہے۔ اس کال بیک کے اندر ہم اپنے تمام افعال کو رجسٹر کرتے ہیں۔ firebase.https رجسٹریشن کے دو طریقے دستیاب ہیں۔ onRequest خام HTTP افعال کے لیے onCall قابل کال افعال کے لیے۔ کہ name پیرامیٹر اس فنکشن کے لیے ایک شناخت کنندہ ہے جو کلاؤڈ رن لاگز میں ظاہر ہوتا ہے اور درخواستوں کو روٹ کرنے کے لیے استعمال ہوتا ہے۔ HttpsOptions کے ساتھ cors: Cors(['*']) رن ٹائم کو تمام ڈومینز سے کراس اوریجن درخواستوں کی اجازت دینے کی ہدایت کرتا ہے۔ یہ ترقی کے دوران ٹھیک ہے، لیکن پیداوار میں اسے مخصوص ڈومینز تک محدود ہونا چاہیے۔ Response.ok(...) دیئے گئے باڈی ٹیکسٹ کے ساتھ HTTP 200 جواب لوٹاتا ہے۔
onRequest کا استعمال کرتے ہوئے HTTP فنکشن
HTTP فنکشنز خام HTTP درخواستوں کا جواب دیتے ہیں۔ یہ سب سے زیادہ لچکدار فنکشن کی قسم ہے کیونکہ یہ آپ کو درخواستوں اور جوابات پر مکمل کنٹرول فراہم کرتا ہے۔ یہ ہیڈرز کا معائنہ کر سکتا ہے، باڈی فارمیٹ کو پارس کر سکتا ہے، اور HTTP رسپانس کوڈ اور باڈی واپس کر سکتا ہے۔
firebase.https.onRequest(
name: 'getUserProfile',
options: const HttpsOptions(
cors: Cors(['https://yourapp.com', 'https://staging.yourapp.com']),
minInstances: 0,
),
(request) async {
if (request.method != 'GET') {
return Response(405, body: 'Method not allowed');
}
final userId = request.url.queryParameters['userId'];
if (userId == null || userId.isEmpty) {
return Response(400, body: 'userId query parameter is required');
}
try {
final doc = await firebase.adminApp
.firestore()
.collection('users')
.doc(userId)
.get();
if (!doc.exists) {
return Response(404, body: 'User not found');
}
return Response.ok(
jsonEncode(doc.data()),
headers: {'content-type': 'application/json'},
);
} catch (e) {
return Response.internalServerError(body: 'Failed to fetch user profile');
}
},
);
cors: Cors([...]) واضح طور پر ان ڈومینز کی فہرست دیتا ہے جہاں سے براؤزر اس فنکشن کو کال کر سکتے ہیں۔ پروڈکشن میں اسے اصل ایپ ڈومین تک محدود کرنا دوسری ویب سائٹس کو آپ کی جانب سے بیک اینڈ پر درخواستیں کرنے سے روکتا ہے۔ minInstances: 0 اس کا مطلب یہ ہے کہ مثالوں کو گرم حالت میں نہیں رکھا جاتا ہے، لہذا آپ کا فنکشن غیر فعالیت کی مدت کے بعد ٹھنڈا شروع ہوسکتا ہے۔ اس قدر کو 1 یا اس سے زیادہ پر سیٹ کرنا یقینی بناتا ہے کہ مثال ہمیشہ فعال رہتی ہے، کولڈ سٹارٹس کو ختم کرتا ہے، لیکن درخواستوں پر کارروائی نہ ہونے پر اخراجات بھی اٹھانا پڑتے ہیں۔ request.method آنے والی درخواست کا HTTP فعل ہے۔ یہاں منتخب کریں اگر آپ چاہتے ہیں کہ یہ اختتامی نقطہ صرف GET درخواستوں کو قبول کرے۔ request.url.queryParameters مندرجہ ذیل طور پر تجزیہ کردہ استفسار کی تار فراہم کریں: Map. Response(405, ...) ایک مخصوص اسٹیٹس کوڈ کے ساتھ HTTP جواب بناتا ہے۔ Response.ok(...) 200 جوابات کے لیے سہولت کنسٹرکٹر۔ headers: {'content-type': 'application/json'} کال کرنے والے کو مطلع کرتا ہے کہ جسم JSON ہے۔ مواد گفت و شنید کا استعمال کرتے ہوئے کسی بھی کلائنٹ کے لیے یہ اہم ہے۔ Response.internalServerError(...) کال کرنے والے کے سامنے اندرونی خرابی کی تفصیلات ظاہر کرنے سے بچنے کے لیے، ہم 500 اسٹیٹس واپس کرتے ہیں جو یہاں کیچ بلاک میں استعمال ہوتا ہے۔
onCall کا استعمال کرتے ہوئے قابل کال افعال
کال ایبل فنکشنز ایک خاص قسم کا HTTP فنکشن ہے جسے فائر بیس کلائنٹ SDK سے براہ راست کال کرنے کے لیے ڈیزائن کیا گیا ہے۔ خام HTTP فنکشنز کے برعکس، کال ایبلز خود بخود Firebase کی توثیق کے سیاق و سباق کو سنبھال لیتے ہیں۔ اگر کال کرنے والے کلائنٹ کے پاس لاگ ان صارف ہے، تو فنکشن صارف کے UID اور ٹوکن کے دعوے وصول کرتا ہے بغیر اجازت کے ہیڈر کو دستی طور پر پارس کئے۔
firebase.https.onCall(
name: 'createPost',
options: const CallableOptions(
cors: Cors(['*']),
),
(request, response) async {
if (request.auth == null) {
throw FirebaseFunctionsException(
code: 'unauthenticated',
message: 'You must be signed in to create a post.',
);
}
final uid = request.auth!.uid;
final data = request.data as Map;
final title = data['title'] as String?;
final content = data['content'] as String?;
if (title == null || title.trim().isEmpty) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: 'Post title is required.',
);
}
if (content == null || content.trim().isEmpty) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: 'Post content is required.',
);
}
final postRef = await firebase.adminApp
.firestore()
.collection('posts')
.add({
'title': title.trim(),
'content': content.trim(),
'authorId': uid,
'createdAt': FieldValue.serverTimestamp(),
});
return CallableResult({'postId': postRef.id, 'success': true});
},
);
request.auth جب کال کرنے والے کلائنٹ میں درخواست میں ایک درست Firebase توثیق ID ٹوکن شامل ہوتا ہے، تو یہ خود بخود Firebase فنکشنز کے رن ٹائم کے ذریعے بھر جاتا ہے۔ اگر بھیجنے والے کی توثیق نہیں ہوئی ہے، request.auth null چیک کریں اور null پھینک دیں۔ FirebaseFunctionsException کوڈ کے ساتھ 'unauthenticated' غیر مستند کال کرنے والوں کو مسترد کرنے کا یہ صحیح نمونہ ہے۔ FirebaseFunctionsException یہاں اہم بات یہ ہے کہ جب آپ کسی فنکشن کو کال ایبل فنکشن کے اندر پھینکتے ہیں، تو Firebase Functions رن ٹائم اسے روکتا ہے اور ایک سٹرکچرڈ ایرر رسپانس بھیجتا ہے جسے کلائنٹ SDK ان پٹ کے طور پر سمجھا سکتا ہے۔ FirebaseFunctionsException اس کا مطلب یہ ہے کہ آپ خام HTTP ایرر باڈی کو پارس کیے بغیر حدود کو عبور کر سکتے ہیں اور مشین کے پڑھنے کے قابل ایرر کوڈ حاصل کر سکتے ہیں۔ request.auth!.uid لاگ ان صارف کی تصدیق شدہ Firebase توثیق UID، جو اجازت کے فیصلوں میں استعمال کرنے کے لیے محفوظ ہے کیونکہ رن ٹائم نے پہلے ہی ٹوکن کی تصدیق کر دی ہے۔ request.data فلٹر کلائنٹ کے ذریعے بھیجا گیا پے لوڈ، درخواست کے باڈی سے ڈی سیریلائز کیا گیا۔ Map. CallableResult(...) واپسی کی قیمت کو کال ایبل پروٹوکول کے ذریعہ متوقع فارمیٹ میں لپیٹیں جو فلٹر کلائنٹ کو ملتا ہے، اس طرح: HttpsCallableResult.data.
موجودہ پابندیاں: آپ کو کیا جاننے کی ضرورت ہے۔
یہ ہینڈ بک کے سب سے اہم حصوں میں سے ایک ہے اور کسی بھی تعمیراتی فیصلے کرنے سے پہلے اسے غور سے پڑھنا چاہیے۔
صرف onRequest اور onCall آپ اسے تقسیم کر سکتے ہیں۔ پس منظر کے محرکات (فائر اسٹور دستاویز کے محرکات، تصدیق کے محرکات، پب/سب ٹرگرز، کلاؤڈ اسٹوریج ٹرگرز، شیڈول کردہ فنکشنز) ترقیاتی مقاصد کے لیے مقامی ایمولیٹر کے اندر چلائے جا سکتے ہیں، لیکن موجودہ تجرباتی ریلیز میں پیداوار کے لیے تعینات نہیں کیے جا سکتے ہیں۔ اگر آپ کا فن تعمیر کسی دستاویز کے بننے پر چلنے والے فائر اسٹور ٹرگرز پر انحصار کرتا ہے، تو آپ کو ان ٹرگرز کو فی الحال Node.js فنکشنز میں رکھنا چاہیے اور Dart میں صرف بزنس لاجک لکھنا چاہیے جس کے لیے بیک گراؤنڈ ٹرگرز کی ضرورت نہیں ہے۔
httpsCallable ڈارٹ کال ایبل فنکشنز کو نام سے نہیں بلایا جا سکتا۔ معیاری Firebase کلائنٹ SDK طریقے FirebaseFunctions.instance.httpsCallable('functionName') سرور کے نام سے فنکشن کی شناخت کرتا ہے۔ یہ شناختی طریقہ کار ڈارٹ فیچرز کی موجودہ ریلیز میں کام نہیں کرتا ہے۔ اس کے بجائے آپ کو استعمال کرنا چاہئے: httpsCallableFromURL تعینات کرتے وقت، آپ کو موصول ہونے والے فنکشن کا مکمل کلاؤڈ رن یو آر ایل پاس کریں۔ یہ ایک بامعنی ورک فلو فرق ہے جو متاثر کرتا ہے کہ آپ اپنے فلٹر کلائنٹ کو کس طرح ترتیب دیتے ہیں۔
مجھے فائر بیس کنسول میں ڈارٹ کی فعالیت نظر نہیں آ رہی ہے۔ اگر آپ ڈارٹ فنکشن لگاتے ہیں اور پھر Firebase کنسول کے فنکشنز سیکشن کو کھولتے ہیں، تو آپ کو فنکشن نظر نہیں آئے گا۔ اپنے تعینات کردہ ڈارٹ فنکشنز کو دیکھنے، ان کا نظم کرنے اور ان کی نگرانی کرنے کے لیے، آپ کو گوگل کلاؤڈ کنسول میں کلاؤڈ رن فنکشنز کے صفحہ پر جانا ہوگا۔ یہ ایک ٹول گیپ ہے جو ممکنہ طور پر پُر ہو جائے گا کیونکہ خصوصیت تجرباتی حیثیت سے باہر ہو جائے گی۔

اپنے فن تعمیر کی منصوبہ بندی کرتے وقت یہ میز آپ کا سب سے اہم حوالہ ہے۔ براہ کرم ڈارٹ سے کمٹمنٹ کرنے سے پہلے "پروڈکشن میں تعینات” کالم کو ان خصوصیات کے لیے پڑھیں جو "نہیں” کے طور پر درج ٹرگر اقسام پر منحصر ہیں۔ تعیناتی کے دوران دریافت ہونے والی حدود کے ارد گرد ڈیزائن کرنا پہلے سے معلوم حدود کے ارد گرد ڈیزائن کرنے سے کہیں زیادہ تکلیف دہ ہے۔
Firebase Admin SDK for Dart
ایڈمن SDK کیا ہے؟
Firebase Admin SDK سرور سائیڈ لائبریریوں کا ایک مجموعہ ہے جو آپ کے فنکشن کوڈ کو اعلیٰ مراعات کے ساتھ Firebase سروسز کے ساتھ تعامل کرنے کی اجازت دیتا ہے۔ Flutter ایپس کے ذریعے استعمال ہونے والے کلائنٹ SDKs Firebase سیکیورٹی کے قوانین کے مطابق کام کرتے ہیں۔ صارفین صرف ان دستاویزات کو پڑھ سکتے ہیں جنہیں پڑھنے کی انہیں اجازت ہے اور وہ صرف ان فیلڈز میں لکھ سکتے ہیں جن میں انہیں ترمیم کرنے کی اجازت ہے۔ ایڈمن SDK حفاظتی اصولوں کو مکمل طور پر نظرانداز کرتا ہے۔ یہ آپ کے Firebase پروجیکٹ تک مکمل انتظامی رسائی کے ساتھ کام کرتا ہے۔
یہی وجہ ہے کہ ایڈمن SDK کوڈ کلائنٹ پر نہیں چلنا چاہیے۔ صرف محفوظ سرور ماحول میں چلتا ہے (کلاؤڈ فنکشنز، کلاؤڈ رن، آپ کے اپنے سرورز) جہاں ایڈمنسٹریٹر تک رسائی دینے والے اسناد محفوظ ہیں۔ کلاؤڈ فنکشنز میں، ایڈمن SDK آپ کے فنکشن کے سروس اکاؤنٹ کا استعمال کرتے ہوئے خود بخود شروع ہو جاتا ہے، بغیر کسی اضافی کنفیگریشن کی ضرورت ہوتی ہے۔
کلاؤڈ فنکشنز کا خودکار آغاز
جب ڈارٹ فنکشن کلاؤڈ فنکشنز کے ماحول میں چلتا ہے، تو ایڈمن SDK خود بخود گوگل ایپلیکیشنز کی ڈیفالٹ اسناد کا استعمال کرتے ہوئے شروع ہو جاتا ہے۔ یہ اسناد آپ کے فنکشن سے وابستہ سروس اکاؤنٹ ہیں جس کو آپ کے Firebase پروجیکٹ تک ایڈمنسٹریٹر کی رسائی حاصل ہے۔ یہ اسناد کو ترتیب نہیں دیتا، سروس اکاؤنٹ JSON فائلوں کو لوڈ کرتا ہے، یا کسی بھی ابتدائی فنکشن کو کال نہیں کرتا ہے۔ یہ صرف کام کرتا ہے۔
await fireUp(args, (firebase) {
firebase.https.onRequest(
name: 'adminExample',
(request) async {
final sensitiveDoc = await firebase.adminApp
.firestore()
.collection('admin_only')
.doc('config')
.get();
return Response.ok(jsonEncode(sensitiveDoc.data()));
},
);
});
firebase.adminApp پہلے سے شروع کردہ ایڈمن SDK مثال۔ بالکل اندر استعمال کیا جا سکتا ہے۔ fireUp کال بیک کی وجہ سے fireUp کلاؤڈ رن ایک سروس اکاؤنٹ کا استعمال کرتا ہے جو کال بیک کے عمل سے پہلے شروع کرنے کے لیے آپ کے فنکشن کے ایگزیکیوشن ماحول سے جڑتا ہے۔ firebase.adminApp.firestore() ڈیٹا بیس میں تمام حفاظتی اصولوں کو نظرانداز کرتے ہوئے، ایڈمنسٹریٹر کی مکمل رسائی کے ساتھ کام کرنے والا ایک Firestore مثال واپس کرتا ہے۔ collection('admin_only').doc('config').get() مجموعوں سے دستاویزات پڑھیں جن تک باقاعدہ کلائنٹ SDK صارفین کو کبھی بھی رسائی حاصل نہیں ہوگی۔ اس کی وجہ یہ ہے کہ وہ دستاویز کی حفاظت کرنے والے حفاظتی اصولوں کے مطابق مسدود ہیں۔ ایڈمن SDK کے پاس یہ حد نہیں ہے۔ یہ سرور سائیڈ کوڈ کی طاقت اور ذمہ داری ہے۔ کوڈ کچھ بھی پڑھ اور لکھ سکتا ہے، اس لیے اسے کلائنٹ پر کبھی نہیں چلنا چاہیے۔
ایڈمن SDK کا استعمال کرتے ہوئے Firestore کے ساتھ کام کرنا
Dart Admin SDK Firestore API فراہم کرتا ہے، بشمول پڑھنا، لکھنا، اپ ڈیٹ کرنا، حذف کرنا، استفسار کرنا اور بیچ آپریشنز۔ API ساختی طور پر کلائنٹ سائیڈ سے ملتا جلتا ہے۔ cloud_firestore یہ ایک جیسا نہیں ہے، لیکن یہ ایک فلٹر پیکیج ہے جس سے آپ فوری طور پر واقف ہوں گے۔
// Reading a single document
final docRef = firebase.adminApp
.firestore()
.collection('posts')
.doc(postId);
final snapshot = await docRef.get();
if (!snapshot.exists) {
return Response(404, body: 'Post not found');
}
final data = snapshot.data()!;
final title = data['title'] as String;
final authorId = data['authorId'] as String;
firebase.adminApp.firestore().collection('posts').doc(postId) نیٹ ورک کال کیے بغیر کسی مخصوص دستاویز کا حوالہ بناتا ہے۔ حوالہ جات ہلکی پھلکی چیزیں ہیں جو فائر اسٹور میں راستے کی وضاحت کرتی ہیں۔ .get() یہ وہ جگہ ہے جہاں اصل نیٹ ورک کالز ہوتی ہیں۔ کہ DocumentSnapshot جس کا .exists پراپرٹی ہمیں بتاتی ہے کہ آیا اس ID کے ساتھ کوئی دستاویز موجود ہے۔ snapshot.data() دستاویز میں درج ذیل فیلڈز کو لوٹاتا ہے: Mapاگر کوئی دستاویز نہیں ہے تو یہ کالعدم ہے۔ کہ ! ~ بعد data() چونکہ آپ نے جانچ پڑتال کی ہے، یہ یہاں ایک محفوظ null دعویٰ ہے۔ .exists اوپر کی لائن میں۔ کاسٹنگ data['title'] as String ڈارٹ ٹائپ کے ساتھ انفرادی فیلڈز نکالیں جس کی آپ توقع کرتے ہیں۔
// Writing a new document with a server-generated ID
final newPostRef = await firebase.adminApp
.firestore()
.collection('posts')
.add({
'title': 'My Post',
'authorId': uid,
'createdAt': FieldValue.serverTimestamp(),
});
final newPostId = newPostRef.id;
.add({...}) مجموعہ میں ایک نئی دستاویز بنائیں اور فائر اسٹور سے اس کے لیے ایک بے ترتیب منفرد ID تیار کریں۔ کہ DocumentReference ایک نئی تخلیق شدہ دستاویز کی طرف اشارہ کرتا ہے۔ newPostRef.id عام طور پر، آپ ایک تیار کردہ ID فراہم کرتے ہیں جسے آپ کلائنٹ کو واپس کرتے ہیں تاکہ یہ نئی دستاویز پر تشریف لے جا سکے یا اس کا حوالہ دے سکے۔ FieldValue.serverTimestamp() ایک سینٹینل ویلیو جو فائر اسٹور کو کلائنٹ یا فنکشن کوڈ میں گھڑی کو استعمال کرنے کے بجائے اس فیلڈ کو سرور کے موجودہ ٹائم اسٹیمپ کے ساتھ تبدیل کرنے کی ہدایت کرتی ہے جب تحریر کا ارتکاب ہوتا ہے۔ یہ یقینی بناتا ہے کہ ٹائم اسٹیمپ سسٹم کی گھڑی کے فرق سے قطع نظر ہمیشہ درست ہوتے ہیں۔
// Updating specific fields in an existing document
await firebase.adminApp
.firestore()
.collection('posts')
.doc(postId)
.update({
'likeCount': FieldValue.increment(1),
'lastModified': FieldValue.serverTimestamp(),
});
.update({...}) صرف ان فیلڈز میں ترمیم کرتا ہے جو آپ بیان کرتے ہیں۔ دستاویز میں دیگر تمام فیلڈز میں کوئی تبدیلی نہیں ہے۔ اگر آپ فیلڈز کے ذیلی سیٹ کو تبدیل کرنا چاہتے ہیں تو یہ کرنا صحیح ہے۔ .set({...}) پوری دستاویز کو صرف آپ کے فراہم کردہ فیلڈز سے بدل دیتا ہے اور کسی بھی فیلڈ کو حذف کر دیتا ہے جو آپ شامل نہیں کرتے ہیں۔ FieldValue.increment(1) ایک اور Firestore سینٹینل جو ایک عددی فیلڈ کو ایک دی گئی رقم سے ایٹمی طور پر بڑھاتا ہے۔ فائر اسٹور سرور پر جوہری طور پر اضافے کو ہینڈل کرتا ہے، موجودہ قیمت کو پڑھتے وقت پیدا ہونے والی نسل کی حالتوں کو روکتا ہے، کسی فنکشن میں قدر شامل کرتا ہے، اور نتیجہ کو واپس لکھتا ہے، جس سے یہ سمورتی تحریروں کے لیے محفوظ ہوتا ہے۔
// Querying with filters and ordering
final querySnapshot = await firebase.adminApp
.firestore()
.collection('posts')
.where('authorId', isEqualTo: uid)
.orderBy('createdAt', descending: true)
.limit(10)
.get();
final posts = querySnapshot.docs.map((doc) {
return {'id': doc.id, ...doc.data()};
}).toList();
.where('authorId', isEqualTo: uid) صرف ان دستاویزات کو واپس کرنے کے لیے استفسار کو فلٹر کریں جو: authorId میدان دیے گئے سے میل کھاتا ہے۔ uid. اکثریت .where() آپ کالز کو جوڑ کر اضافی فلٹرز شامل کر سکتے ہیں۔ .orderBy('createdAt', descending: true) نتائج کے لحاظ سے ترتیب دیں۔ createdAt میدان، تازہ ترین۔ جب آپ استعمال کرتے ہیں orderBy فیلڈز کے لیے، Firestore کو ان فیلڈز کو انڈیکس کرنے کی ضرورت ہوتی ہے اور یہ آسان سوالات کے لیے خود بخود کرتا ہے۔ .limit(10) غیر محدود پڑھنے سے بچنے کے لیے، ہم نتائج کو 10 دستاویزات تک محدود کرتے ہیں۔ querySnapshot.docs یہ فہرست ہے۔ DocumentSnapshot اعتراض سے مماثل اشیاء۔ ہر دستاویز کا نقشہ بنائیں {'id': doc.id, ...doc.data()} خود کار طریقے سے تیار کردہ دستاویز IDs (دستاویز فیلڈ کے اندر محفوظ نہیں) اور دستاویز فیلڈ ڈیٹا کو ایک ہی نقشے میں جوڑتا ہے۔
// Batch writes: multiple operations committed atomically
final batch = firebase.adminApp.firestore().batch();
batch.set(
firebase.adminApp.firestore().collection('posts').doc(newPostId),
{'title': 'New Post', 'authorId': uid},
);
batch.update(
firebase.adminApp.firestore().collection('users').doc(uid),
{'postCount': FieldValue.increment(1)},
);
await batch.commit();
firestore().batch() نسل WriteBatch Firestore پر ایک ساتھ بھیجنے سے پہلے متعدد تحریری کارروائیوں کو جمع کرتا ہے۔ batch.set(...) اور batch.update(...) کاموں کو فوری طور پر انجام دینے کے بجائے قطار میں شامل کرتا ہے۔ batch.commit() یہ وہ جگہ ہے جہاں تمام زیر التواء کارروائیاں فائر اسٹور کو بھیجی جاتی ہیں اور جوہری طور پر انجام دی جاتی ہیں۔ اگر آپریشن ناکام ہو جاتا ہے، تو سب کچھ واپس لے لیا جاتا ہے۔ یہ صحیح نمونہ ہے جب بھی آپ کی کاروباری منطق کے لیے متعدد دستاویزات کو ایک اکائی کے طور پر ایک ساتھ تبدیل کرنے کی ضرورت ہوتی ہے، جیسے کہ ایک ہی وقت میں پوسٹس بناتے وقت مصنف کی پوسٹ کی تعداد میں اضافہ کرنا۔ بیچنگ کے بغیر، دونوں کارروائیوں کے درمیان تنازعات ڈیٹا بیس کو متضاد حالت میں چھوڑ دیں گے۔
ایڈمن SDK کا استعمال کرتے ہوئے تصدیق کی کارروائیاں
ایڈمن SDK آئی ڈی ٹوکنز کی تصدیق کرنے، یو آئی ڈی یا ای میل کے ذریعے صارفین کو تلاش کرنے، صارفین کو تخلیق کرنے اور حذف کرنے، اور صارف کے ٹوکنز کے لیے حسب ضرورت دعوے سیٹ کرنے کے فنکشن فراہم کرتا ہے۔ ان کارروائیوں کے لیے ایڈمنسٹریٹر کی مراعات کی ضرورت ہوتی ہے، جو کلائنٹ SDK کے پاس نہیں ہے۔
firebase.https.onRequest(
name: 'securedEndpoint',
(request) async {
final authHeader = request.headers['authorization'];
if (authHeader == null || !authHeader.startsWith('Bearer ')) {
return Response(401, body: 'Unauthorized');
}
final idToken = authHeader.substring(7);
try {
final decodedToken = await firebase.adminApp
.auth()
.verifyIdToken(idToken);
final uid = decodedToken.uid;
return Response.ok(jsonEncode({'uid': uid, 'success': true}));
} on FirebaseAuthException catch (e) {
return Response(401, body: 'Invalid or expired token: ${e.message}');
}
},
);
request.headers['authorization'] آنے والی HTTP درخواستوں سے اجازت کا ہیڈر پڑھیں۔ Firebase توثیق ID ٹوکن بیئرر ٹوکن کے طور پر بھیجا جاتا ہے۔ یعنی ہیڈر ویلیو ایک سٹرنگ ہے۔ "Bearer " ایک ٹوکن مندرجہ ذیل ہے۔ .startsWith('Bearer ') ٹوکن نکالنے کی کوشش کرنے سے پہلے فارمیٹ کی توثیق کی جاتی ہے۔ .substring(7) پٹی "Bearer " خام ٹوکن سٹرنگ بازیافت کرنے کے لیے سابقہ (7 حروف)۔ firebase.adminApp.auth().verifyIdToken(idToken) ٹوکن کو Firebase Token Verification سروس کو بھیجیں، جو دستخط کی توثیق کرتی ہے، اس بات کو یقینی بناتی ہے کہ اس کی میعاد ختم نہیں ہوئی ہے، اور اس بات کی تصدیق کرتی ہے کہ اسے آپ کے Firebase پروجیکٹ نے جاری کیا تھا۔ اگر تصدیق کامیاب ہو جاتی ہے۔ DecodedIdToken صارف کی UID اور حسب ضرورت دعوے پر مشتمل ہے۔ اگر ٹوکن غلط ہے یا ختم ہو گیا ہے۔ FirebaseAuthExceptionہم اسے پکڑتے ہیں اور اسے 401 جواب میں تبدیل کرتے ہیں۔ یہ پیٹرن خاص طور پر لاگو ہوتا ہے: onRequest اس خصوصیت کے لیے آپ کو یہ جاننے کی ضرورت ہے کہ کال کرنے والا کون ہے۔ کے لیے onCall اگر آپ فنکشنز استعمال کرتے ہیں، تو یہ پورا بہاؤ رن ٹائم کے ذریعے خود بخود ہینڈل ہوجاتا ہے۔ یہ خام HTTP فنکشنز پر کال ایبل فنکشنز استعمال کرنے کا ایک اہم فائدہ ہے۔
await firebase.adminApp
.auth()
.setCustomUserClaims(uid, {'role': 'admin', 'premiumUser': true});
setCustomUserClaims(uid, {...}) صارف کے Firebase توثیق ٹوکن کے ساتھ صوابدیدی کلیدی قدر کا ڈیٹا منسلک کریں۔ یہ ڈیٹا کسی بھی ID ٹوکن میں شامل کیا جائے گا جو صارف بعد میں حاصل کرتا ہے اور اسے ایڈمن SDK کوڈ میں اس طرح استعمال کیا جا سکتا ہے: decodedToken.claims آپ کے Firestore کے حفاظتی اصولوں میں: request.auth.token.role. اپنی مرضی کے دعوے Firebase ایپلی کیشنز میں رول پر مبنی رسائی کنٹرول کو نافذ کرنے کا معیاری طریقہ ہیں۔ اگلی بار صارف ٹوکن کے تازہ ہونے پر دعویٰ لاگو کیا جائے گا۔ یہ ہر گھنٹے خود بخود ہوتا ہے۔ متبادل طور پر، آپ کال کے ذریعے زبردستی ریفریش کر سکتے ہیں: user.getIdToken(true) کلائنٹ سے۔
ڈارٹ کلاؤڈ کی خصوصیات کو ترتیب دینا: قدم بہ قدم
مرحلہ 1: تجرباتی خصوصیات کو فعال کریں۔
ڈارٹ سپورٹ تجرباتی ہے اور اسے Firebase CLI میں فیچر فلیگز کے ذریعے کنٹرول کیا جاتا ہے۔ سیٹ اپ کے دوران CLI ڈارٹ کو بطور آپشن پیش کرنے سے پہلے جھنڈا فعال ہونا چاہیے۔
firebase experiments:enable dartfunctions
یہ کمانڈ آپ کی مقامی Firebase CLI کنفیگریشن فائل میں ایک جھنڈا لکھتی ہے۔ یہ ایک وقتی سیٹ اپ مرحلہ ہے جو ایک ہی سسٹم پر پروجیکٹس اور ٹرمینلز میں برقرار رہتا ہے۔
firebase experiments
اس کمانڈ کو چلانے سے موجودہ تمام فعال تجربات کی فہرست بن جائے گی تاکہ آپ دیکھ سکیں: dartfunctions جاری رکھنے سے پہلے آؤٹ پٹ میں ظاہر ہوتا ہے۔ اگر یہ ظاہر نہیں ہوتا ہے، firebase init functions درج ذیل مراحل میں موجود کمانڈز ڈارٹ کو بطور لینگویج آپشن پیش نہیں کرتی ہیں۔ یہ سب سے عام پہلی بار سیٹ اپ کی ناکامی ہے۔
مرحلہ 2: اپنا CLI ورژن چیک کریں۔
Dart Cloud Functions کے لیے Firebase CLI ورژن 15.15.0 یا اس سے زیادہ کی ضرورت ہے۔
firebase --version
یہ کمانڈ موجودہ انسٹال شدہ CLI ورژن پرنٹ کرتی ہے۔ اگر آؤٹ پٹ 15.15.0 سے کم ہے تو جاری رکھنے سے پہلے اپ ڈیٹ کمانڈ چلائیں۔
npm install -g firebase-tools
یہ Firebase CLI کو آپ کی مشینوں پر تازہ ترین ورژن میں اپ ڈیٹ کر دے گا۔ کہ -g جھنڈے عالمی سطح پر نصب کیے جاتے ہیں، لہذا firebase کمانڈ کسی بھی ڈائریکٹری سے حاصل کی جا سکتی ہے۔
firebase login
CLI کو اپ ڈیٹ کرنے کے بعد، آپ اس بات کو یقینی بنانے کے لیے دوبارہ لاگ ان کر سکتے ہیں کہ آپ کی تصدیق کی اسناد تازہ ترین ہیں اور درست Google اکاؤنٹ سے وابستہ ہیں۔ اگر آپ نے حال ہی میں پہلے ہی لاگ ان کیا ہے اور آپ کو یقین ہے کہ آپ کی اسناد تازہ ترین ہیں، تو یہ مرحلہ چھوڑ دیں۔
مرحلہ 3: ڈارٹ کا استعمال کرتے ہوئے کلاؤڈ فنکشنز کو شروع کریں۔
firebase init functions
جب CLI آپ کو کسی زبان کے لیے اشارہ کرے تو اگلا منتخب کریں۔ ڈارٹ. جب انحصار کو انسٹال کرنے کا اشارہ کیا جائے تو، اگلا کو منتخب کریں۔ ہاں. CLI مندرجہ ذیل ڈھانچہ تیار کرتا ہے:

functions/bin/server.dart یہ ایک داخلی نقطہ ہے۔ Firebase CLI جانتا ہے کہ اسے درج ذیل وجوہات کی بنا پر یہاں دیکھنے کی ضرورت ہے: firebase.json اسے پوائنٹ کرنے کے لیے ترتیب دیا گیا ہے۔ functions/lib/ یہ وہ جگہ ہے جہاں آپ اضافی ڈارٹ فائلیں ڈالتے ہیں۔ server.dart فنکشنز کی تعداد بڑھنے کے ساتھ فنکشن منطق کو منظم رکھنے کے لیے درآمدات انجام دیں۔ functions/pubspec.yaml فلٹر ایپ سے الگ فنکشن کوڈ بیس کے لیے ڈارٹ پیکیج مینی فیسٹ۔ pubspec.yaml. firebase.json CLI کے ذریعے فنکشن کنفیگریشن کو شامل کرنے کے لیے اپ ڈیٹ کیا گیا، بشمول مرتب کردہ بائنری پاتھز اور رن ٹائم سیٹنگز۔
پیدا کیا server.dart ایک کام کرنے والی "ہیلو ورلڈ” خصوصیت پر مشتمل ہے جسے آپ اپنی ترتیبات کی تصدیق کے لیے فوری طور پر چلا سکتے ہیں۔
import 'package:firebase_functions/firebase_functions.dart';
void main(List args) async {
await fireUp(args, (firebase) {
firebase.https.onRequest(
name: 'helloWorld',
options: const HttpsOptions(cors: Cors(['*'])),
(request) async {
return Response.ok('Hello from Dart Cloud Functions!');
},
);
});
}
یہ ایک کم سے کم لیکن مکمل ڈارٹ کلاؤڈ فیچر ہے۔ کہ main فنکشن کمانڈ لائن لیتا ہے۔ args بائنری شروع کرتے وقت کلاؤڈ فنکشنز کا رن ٹائم گزر جانے والی صف۔ fireUp پورٹ کنفیگریشن پڑھیں۔ کہ onRequest رجسٹریشن ایک فنکشن کا نام اور ہینڈلر فراہم کرتا ہے جو 200 اسٹیٹس اور سادہ ٹیکسٹ باڈی کے ساتھ ہر HTTP درخواست کا جواب دیتا ہے۔ اسے مقامی طور پر چلانے سے یہ یقینی بنتا ہے کہ ایمولیٹر زیادہ پیچیدہ منطق میں وقت لگانے سے پہلے فنکشن کو مرتب اور شروع کر سکتا ہے۔
مرحلہ 4: مقامی ایمولیٹر چلائیں۔
firebase emulators:start
ایمولیٹر کچھ اس طرح شروع اور آؤٹ پٹ کرتا ہے:

firebase emulators:start تمام ترتیب شدہ ایمولیٹرز شروع کریں۔ firebase.json. ڈارٹ ایمولیٹر سرور کو شروع کرنے سے پہلے مقامی طور پر افعال کو مرتب کرتا ہے، لہذا آپ کو ایک مختصر تعمیراتی مرحلے کے بعد "تیار ڈارٹ ایمولیٹر” لائن نظر آئے گی۔ فنکشن ایمولیٹر پورٹ 5001 پر بطور ڈیفالٹ چلتا ہے۔ فائر اسٹور ایمولیٹر پورٹ 8080 پر چلتا ہے، اور آپ کا فنکشن کوڈ ایمولیٹر کے اندر چلنے پر پروڈکشن ڈیٹا بیس کی بجائے ایمولیٹڈ فائر اسٹور سے خود بخود جڑ جاتا ہے۔ آپ کا helloWorld فنکشن کو اس سے بلایا جا سکتا ہے: http://127.0.0.1:5001/your-project-id/us-central1/helloWorld. ڈارٹ ایمولیٹر کا ایک قابل ذکر فائدہ گرم دوبارہ لوڈ کرنا ہے۔ .dart اگر فائل موجود ہے تو، ایمولیٹر تبدیلی کا پتہ لگائے گا اور خود بخود دوبارہ کمپائل اور فنکشن کو دوبارہ شروع کر دے گا، بغیر آپ کو کوئی کمانڈ چلائے۔
مرحلہ 5: اپنی فلٹر ایپ کو ایمولیٹر سے جوڑیں۔
import 'package:cloud_functions/cloud_functions.dart';
void _connectToEmulators() {
FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001);
}
useFunctionsEmulator('localhost', 5001) آپ کے فلٹر ایپ کے فائربیس فنکشنز کلائنٹ کو ہدایت کرتا ہے کہ تمام فنکشن کالز پروڈکشن کے بجائے پورٹ 5001 پر مقامی ایمولیٹر کو بھیجیں۔ عام طور پر، آپ اپنی ایپ میں کسی بھی فنکشن کال کرنے سے پہلے اسے کال کرتے ہیں۔ main() اس کے فوراً بعد Firebase.initializeApp(). یہ طریقہ صرف فنکشن کالز کو متاثر کرتا ہے، فائر اسٹور یا تصدیق پر نہیں، اور اگر آپ اس کی تقلید کرنا چاہتے ہیں تو اس کا اپنا مساوی طریقہ ہے۔
if (Platform.isAndroid) {
FirebaseFunctions.instance.useFunctionsEmulator('10.0.2.2', 5001);
} else {
FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001);
}
اینڈروئیڈ ایمولیٹر ورچوئل مشین کے اندر اپنے نیٹ ورک کے نام کی جگہ کے ساتھ چلتا ہے۔ اینڈرائیڈ ایمولیٹر کے نقطہ نظر سے: localhost اس سے مراد خود ایمولیٹر ہے، ترقی کی مشین نہیں۔ خصوصی پتہ 10.0.2.2 اس طرح اینڈرائیڈ ایمولیٹر ہوسٹ سسٹم تک پہنچتا ہے۔ localhost. iOS سمیلیٹر کو یہ مسئلہ نہیں ہے کیونکہ یہ میزبان کمپیوٹر کے نیٹ ورک کو شیئر کرتا ہے۔ localhost یہ وہاں صحیح طریقے سے کام کرتا ہے۔ کہ Platform.isAndroid چیک رن ٹائم پر صحیح پتہ کا انتخاب کرتا ہے، جس سے ترقی کے دوران دونوں پلیٹ فارمز پر ایک ہی کوڈ کو صحیح طریقے سے کام کرنے کی اجازت ملتی ہے۔
مرحلہ 6: پروڈکشن میں تعینات کریں۔
firebase deploy --only functions
کہ --only functions جھنڈا CLI سے کہتا ہے کہ وہ صرف فنکشن کو تعینات کرے اور فائر بیس کے دیگر وسائل (فائر اسٹور رولز، ہوسٹنگ وغیرہ) کو چھوڑ دے۔ ڈارٹ کی تعیناتی کا عمل Node.js سے بالکل مختلف ہے۔ اس کا مطلب ہے کہ Firebase CLI چلے گا۔ dart compile exe اپنی ڈویلپمنٹ مشین پر مقامی بائنریز بنائیں۔ پھر اس بائنری کو کلاؤڈ رن پر اپ لوڈ کریں۔ تعیناتی آؤٹ پٹ میں تعینات فنکشن کا URL شامل ہوتا ہے۔
✔ functions: Finished running predeploy script.
✔ functions: helloWorld(us-central1) deployed successfully.
Function URL (helloWorld(us-central1)):
https://helloworld-abc123def456-uc.a.run.app
اس URL کو محفوظ کریں۔ موجودہ ارد گرد کی پابندیوں کی وجہ سے httpsCallable نام کے حل کے لیے، آپ کو فلٹر میں کسی فنکشن کو کال کرتے وقت براہ راست اس URL کو پاس کرنا ہوگا۔ یو آر ایل کی ہیش (abc123def456) ہر پروجیکٹ اور فنکشن کے لیے منفرد ہے اور اسی فنکشن کو تعینات کرتے وقت تبدیل نہیں ہوتا ہے، اس لیے اسے اپنی فلٹر ایپ میں ہارڈ کوڈ کرنا یا Firebase Remote Config سے لوڈ کرنا محفوظ ہے۔
فلٹر سے ڈارٹ فنکشنز کو کال کرنا
httpsCallableFromURL کا استعمال کرتے ہوئے کال کریں۔
کیونکہ httpsCallable('functionName') یہ موجودہ ریلیز میں ڈارٹ کی خصوصیات کے ساتھ کام نہیں کرتا ہے۔ httpsCallableFromURL اس کے بجائے، مکمل کلاؤڈ رن یو آر ایل استعمال کریں۔
// lib/services/functions_service.dart
import 'package:cloud_functions/cloud_functions.dart';
class FunctionsService {
static const _createPostUrl="https://createpost-abc123def456-uc.a.run.app";
static const _getUserProfileUrl="https://getuserprofile-abc123def456-uc.a.run.app";
Future createPost({
required String title,
required String content,
}) async {
try {
final callable = FirebaseFunctions.instance.httpsCallableFromURL(
_createPostUrl,
);
final result = await callable.call({
'title': title,
'content': content,
});
return result.data['postId'] as String;
} on FirebaseFunctionsException catch (e) {
throw _mapFunctionException(e);
}
}
Exception _mapFunctionException(FirebaseFunctionsException e) {
switch (e.code) {
case 'unauthenticated':
return UnauthorizedException('Please sign in to continue.');
case 'invalid-argument':
return ValidationException(e.message ?? 'Invalid input.');
case 'not-found':
return NotFoundException(e.message ?? 'Resource not found.');
default:
return ServerException(
e.message ?? 'An unexpected error occurred.',
);
}
}
}
اپنے فنکشن یو آر ایل کو حسب ذیل مرکزی بنائیں: static const سروس کلاس کے اوپری حصے میں ایک سٹرنگ کا مطلب ہے کہ سروس ایک جگہ پر ہے، تلاش کرنا آسان ہے اور اپ ڈیٹ کرنا آسان ہے۔ بڑی ایپس کے لیے، ہم Firebase Remote Config سے لوڈ کرنے کی تجویز کرتے ہیں تاکہ آپ ایپ کا نیا ورژن جاری کیے بغیر URLs کو اپ ڈیٹ کر سکیں۔ FirebaseFunctions.instance.httpsCallableFromURL(_createPostUrl) نسل HttpsCallable دیئے گئے یو آر ایل کو نشانہ بنانے والی چیز۔ یہ آبجیکٹ پروٹوکول کی تمام تفصیلات کو کال ایبل فنکشن فارم میں سمیٹتا ہے، بشمول ڈیٹا کو درخواست کے باڈی میں سیریلائز کرنا اور جواب کو ڈی سیریلائز کرنا۔ callable.call({...}) فنکشن کال پر عمل کریں اور نقشہ کو درخواست پے لوڈ کے طور پر بھیجیں۔ HttpsCallableResult فنکشن مکمل ہونے کے بعد۔ result.data چاندی Map کی طرف سے واپس CallableResult(...) سرور پر۔ کچھ پرکشش FirebaseFunctionsException کسی بھی ساختی خرابیوں کو پکڑیں۔ FirebaseFunctionsException سرور پر۔ e.code یہ مشین پڑھنے کے قابل ایرر کوڈ ہے۔ _mapFunctionException Firebase کی مخصوص اقسام کو اپنی کاروباری منطق سے دور رکھتے ہوئے، انہیں اپنی ایپ کے اپنے استثنائی درجہ بندی میں ٹائپ شدہ ڈومین استثناء میں تبدیل کریں۔
HTTP افعال کو براہ راست کال کرنا
کے لیے onRequest HTTP فنکشنز کو ڈارٹ کا استعمال کرتے ہوئے کسی دوسرے HTTP اینڈ پوائنٹ کی طرح کہا جاتا ہے۔ http پیکیج:
import 'package:http/http.dart' as http;
import 'dart:convert';
class ProfileService {
static const _getUserProfileUrl="https://getuserprofile-abc123def456-uc.a.run.app";
Future
FirebaseAuth.instance.currentUser نیٹ ورک کال کیے بغیر مقامی Firebase تصدیقی کیشے سے فی الحال لاگ ان صارف کو بازیافت کرتا ہے۔ user?.getIdToken() صارف کا موجودہ ID ٹوکن حاصل کرتا ہے اور اگر اس کی میعاد ختم ہو گئی ہے تو اسے تازہ کرتا ہے۔ کہ ? اس کا مطلب یہ ہے کہ اگر کوئی صارف لاگ ان نہیں ہوتا ہے تو null واپس کر دیا جائے گا اور مشروط ہیڈر داخل کرنے کو عام طور پر ہینڈل کیا جائے گا۔ if (idToken != null) 'Authorization': 'Bearer (idToken' یہ ڈارٹ کلیکشن ہے۔ if نحو میں مشروط طور پر اجازت کا ہیڈر شامل کرنا صرف اس صورت میں جب ٹوکن دستیاب ہو۔ یہ ایک ہی سروس کے طریقہ کار کو تصدیق شدہ اور گمنام دونوں درخواستوں کے لیے کام کرنے کی اجازت دیتا ہے جب کوئی ٹوکن نہ ہو تو صرف ہیڈر کو چھوڑ کر۔ Uri.parse(')_getUserProfileUrl?userId=$userId') URL میں استفسار کے پیرامیٹرز شامل کریں۔ jsonDecode(response.body) as Map JSON رسپانس باڈی کو ڈارٹ میپ میں پارس کریں۔ اگر اسٹیٹس کوڈ 200 نہیں ہے۔ ServerException اسے ڈیبگنگ کے مقاصد کے لیے شامل اسٹیٹس کوڈ کے ساتھ اٹھایا گیا ہے۔
مشترکہ پیکیج: ڈیٹا ماڈل ڈیڈپلیکیشن
مشترکہ پیکجز مکمل اسٹیک ڈارٹ اسٹوری کا ساختی لحاظ سے اہم ترین حصہ ہیں۔ یہ ایک اسٹینڈ اسٹون ڈارٹ پیکیج ہے جس میں کوئی فلٹر انحصار نہیں ہے اور نہ ہی کوئی فائربیس انحصار ہے جو کہ ڈیٹا ماڈل، توثیق کی منطق، مستقل، اور یوٹیلیٹی فنکشنز کی وضاحت کرتا ہے جو کلاؤڈ فنکشنز بیک اینڈ اور فلٹر فرنٹ اینڈ دونوں کے ذریعہ استعمال ہوتا ہے۔
مشترکہ پیکج بنائیں
dart create --template=package packages/shared
dart create --template=package معیاری لائبریری لے آؤٹ کا استعمال کرتے ہوئے ایک نیا ڈارٹ پیکیج بنائیں۔ lib/ عوامی کوڈ کے لیے ڈائریکٹری؛ test/ ڈائریکٹری اور pubspec.yaml. کہ packages/shared راستہ اندر رکھا ہوا ہے۔ packages/ پراجیکٹ روٹ میں ایک فولڈر، جو کہ ایک ریپوزٹری ڈھانچے میں اندرونی پیکجوں کے لیے مخصوص جگہ ہے۔ جب آپ اس کمانڈ کو چلاتے ہیں، تو آپ کے پروجیکٹ کا ڈھانچہ اس طرح نظر آئے گا:

مشترکہ pubspec.yaml یہ جان بوجھ کر کم سے کم ہے۔
name: shared
description: Shared data models and logic for the Kopa app.
version: 0.1.0
environment:
sdk: ^3.0.0
dependencies:
json_annotation: ^4.8.0
dev_dependencies:
build_runner: ^2.4.0
json_serializable: ^6.7.0
test: ^1.24.0
اس کی سب سے اہم خصوصیت یہ ہے۔ pubspec.yaml کیا غائب ہے: کوئی نہیں۔ flutterنہیں firebase_coreنہیں firebase_functionsاور نہیں cloud_firestore. مشترکہ پیکجوں کا انحصار صرف خالص ڈارٹ لائبریریوں پر ہوتا ہے۔ یہی چیز سرور سائیڈ فنکشن پیکج اور فلٹر ایپ دونوں سے بیک وقت ورژن میں تنازعات پیدا کیے بغیر درآمد کرنا ممکن بناتی ہے۔ json_annotation پیشکش @JsonSerializable() ماڈل کلاسز کے لیے استعمال شدہ تشریح۔ json_serializable ایک بلڈ ٹائم کوڈ جنریٹر جو ان تبصروں کو پڑھتا ہے اور تیار کرتا ہے۔ fromJson/toJson یہ طریقہ صرف ترقی کے دوران چلتا ہے، رن ٹائم نہیں، لہذا اسے ترقیاتی انحصار کے طور پر درج کیا گیا ہے۔ build_runner یہ ایک ایسا ٹول ہے جو کوڈ جنریٹر چلاتا ہے اور ایک ڈویلپمنٹ انحصار بھی ہے۔ test مشترکہ منطق کی یونٹ ٹیسٹنگ کو فعال کرتا ہے۔
مشترکہ ماڈل کی تعریف
// packages/shared/lib/src/models/post.dart
import 'package:json_annotation/json_annotation.dart';
part 'post.g.dart';
@JsonSerializable()
class Post {
final String id;
final String title;
final String content;
final String authorId;
final int likeCount;
final DateTime createdAt;
const Post({
required this.id,
required this.title,
required this.content,
required this.authorId,
required this.likeCount,
required this.createdAt,
});
factory Post.fromJson(Map json) => _$PostFromJson(json);
Map toJson() => _$PostToJson(this);
}
part 'post.g.dart' ہم اعلان کرتے ہیں کہ ہمارے پاس درج ذیل فائلیں تیار کی گئی ہیں: post.g.dart یہ لائبریری کا حصہ ہے۔ کہ json_serializable کوڈ جنریٹر اس فائل کو چلانے پر تیار کرتا ہے۔ dart run build_runner build. @JsonSerializable() یہ آپ کو بتانے کے لیے ایک نوٹ ہے۔ json_serializable اس کلاس کے لیے سیریلائزیشن کوڈ تیار کریں۔ تمام فیلڈز ہیں۔ final اس کی وجہ یہ ہے کہ ماڈل آبجیکٹ کو ناقابل تغیر ہونا چاہیے۔ ایک بار تخلیق کیا Post یہ موقع پر تبدیل نہیں ہوتا ہے۔ آپ نئے ہیں Post اس کے بجائے ایک مختلف قدر استعمال کریں۔ استعمال کریں DateTime کے لیے createdAt خام کی بجائے int ٹائم اسٹیمپ یا String اپنے ماڈلز کو تجرید کی مناسب سطح پر رکھیں۔ فلٹر ایپس اور فنکشنز دونوں کے درمیان تبدیل ہوتے ہیں: DateTime مخصوص ٹائم اسٹیمپ فارمیٹس کو مقامی رکھ کر، مشترکہ ماڈل دونوں فریقوں کے لیے پریشانی سے پاک رہتا ہے۔ factory Post.fromJson(...) اور toJson() تخلیق کردہ صارف کو تفویض کریں۔ _(PostFromJson اور _)PostToJson سیریلائزیشن کو ہٹانے کے لیے فنکشن کا استعمال کریں جو آپ نے خود لکھا ہے۔ دستی طور پر لکھی گئی سیریلائزیشن زیادہ تر ڈیٹا کنٹریکٹ کیڑے کا سبب بنتی ہے (گمشدہ فیلڈز، غلط کلیدی نام، بھولے ہوئے null چیک وغیرہ)۔ کوڈ جنریشن غلطیوں کے پورے زمرے کو ختم کرتی ہے۔
// packages/shared/lib/src/validation/post_validation.dart
class PostValidation {
static const int titleMaxLength = 120;
static const int contentMaxLength = 10000;
static const int titleMinLength = 3;
static String? validateTitle(String? title) {
if (title == null || title.trim().isEmpty) {
return 'Title is required.';
}
if (title.trim().length < titleMinLength) {
return 'Title must be at least $titleMinLength characters.';
}
if (title.trim().length > titleMaxLength) {
return 'Title cannot exceed $titleMaxLength characters.';
}
return null;
}
static String? validateContent(String? content) {
if (content == null || content.trim().isEmpty) {
return 'Content is required.';
}
if (content.trim().length > contentMaxLength) {
return 'Content cannot exceed $contentMaxLength characters.';
}
return null;
}
static bool isValid({required String title, required String content}) {
return validateTitle(title) == null && validateContent(content) == null;
}
}
تمام ممبران static کیونکہ PostValidation یہ فنکشنز کے لیے نام کی جگہ ہے، نہ کہ وہ کلاس جس کو آپ انسٹیٹیوٹ کر رہے ہیں۔ لمبائی مستقل titleMaxLength، contentMaxLengthاور titleMinLength ہے static constاس کا مطلب ہے کہ یہ کمپائل ٹائم پر موجود ہے، رن ٹائم پر کوئی میموری استعمال نہیں کرتا، اور رن ٹائم توثیق منطق اور فلٹر ویجیٹ کنفیگریشن دونوں میں استعمال کیا جا سکتا ہے، جیسے maxLength پیرامیٹر TextField)۔ ہر توثیق کرنے والا فارم کی تصدیق کرنے والوں کے لیے ڈارٹ کے اصولوں پر عمل کرتا ہے۔ null جائز کا مطلب ہے String اس کا مطلب ہے کہ یہ اس غلطی کے پیغام کے ساتھ غلط ہے۔ کہ validateTitle طریقہ کال .trim() اسپیس پیڈڈ تاروں کو لمبائی کی توثیق سے گزرنے سے روکنے کے لیے لمبائی کی جانچ کرنے سے پہلے۔ کہ isValid سہولت کے طریقے ان کال کرنے والوں کو اجازت دیتے ہیں جنہیں صرف بولین کی ضرورت ہوتی ہے (ایک غلطی کے پیغام کے برعکس) ایک کال میں دونوں فیلڈز کو چیک کرنے کے لیے، جیسے کہ جمع کرانے والے بٹن کو فعال یا غیر فعال کرنا۔
// packages/shared/lib/src/constants/api_constants.dart
class ApiConstants {
static const String createPostFunction = 'createPost';
static const String getUserProfileFunction = 'getUserProfile';
static const String likePostFunction = 'likePost';
static const String postsCollection = 'posts';
static const String usersCollection = 'users';
}
ApiConstants فنکشن کے ناموں اور اسٹیک کے دونوں طرف حوالہ کردہ Firestore مجموعہ کے ناموں کے لیے سٹرنگ شناخت کنندگان کو اسٹور کریں۔ آپ کے کوڈ میں بکھرے ہوئے سٹرنگ لٹریلز کے بجائے مستقل استعمال کرنے سے ٹائپنگ کی غلطیوں، نام بدلنے پر ایک جگہ اپ ڈیٹ ہونے سے بچتا ہے، اور کمپائلر آپ کو وہ تمام جگہیں دکھاتا ہے جنہیں آپ نے استعمال کیا ہے۔ فنکشن کا نام مستقل استعمال کیا جاتا ہے: firebase.https.onRequest(name: ApiConstants.createPostFunction) سرور اور یو آر ایل کنفیگریشن یا کلائنٹ لاگ ان میں۔ جمع کرنے کے نام کے مستقل اس بات کو یقینی بناتے ہیں کہ سرور اور کلائنٹ ہمیشہ ایک ہی نام کے ساتھ کسی مجموعہ کو لکھتے اور پڑھتے ہیں، کیڑے کی ایک کلاس کو روکتے ہیں جہاں فنکشن لکھتے ہیں۔ "Posts" کیپیٹل P کے ساتھ کلائنٹ کے سوالات "posts" چھوٹے حروف کے ساتھ p.
// packages/shared/lib/shared.dart
export 'src/models/post.dart';
export 'src/models/user.dart';
export 'src/validation/post_validation.dart';
export 'src/constants/api_constants.dart';
یہ ایک بیرل فائل ہے۔ پیکج فراہم کردہ ہر چیز کو ایک ہی امپورٹ پوائنٹ کے ذریعے واپس ایکسپورٹ کریں۔ پیکیج صارفین لکھتے ہیں۔ import 'package:shared/shared.dart' فوری رسائی حاصل کریں۔ Post، PostValidation، ApiConstantsاور باقی سب کچھ پیکج برآمد کرتا ہے۔ بیرل فائل کے بغیر، صارف کو اندرونی ڈائرکٹری کا ڈھانچہ جاننا ہوگا اور ہر فائل کو انفرادی طور پر لانا ہوگا، ایک تفصیل جسے پیکیج کو چھپانا ضروری ہے۔
کسی فنکشن میں مشترکہ پیکیج کا حوالہ دیں۔
# functions/pubspec.yaml
name: kopa_functions
version: 0.1.0
environment:
sdk: ^3.0.0
dependencies:
firebase_functions: ^0.1.0
google_cloud_firestore: ^0.1.0
shared:
path: ../packages/shared
shared: path: ../packages/shared یہ راستے پر انحصار ہے۔ یہ ڈارٹ پب ٹول کو درج ذیل مسائل کو حل کرنے کی ہدایت کرتا ہے۔ shared پیکیج کو فائل سسٹم سے pub.dev کے بجائے دیئے گئے رشتہ دار راستے پر درآمد کریں۔ چینل ../packages/shared سے ایک سطح اوپر جائیں۔ functions/ پروجیکٹ کی جڑ پر جائیں اور پھر نیچے packages/shared/. جب Firebase CLI تعیناتی کے لیے ڈارٹ فنکشن کو مرتب کرتا ہے، تو یہ آپ کی ڈیولپمنٹ مشین پر اس راستے کے انحصار کو مقامی طور پر حل کرتا ہے اور اسے مرتب شدہ بائنری کے ساتھ بنڈل کرتا ہے، اس لیے یہ مقامی راستے کا حوالہ ہونے کے باوجود پروڈکشن میں صحیح طریقے سے کام کرتا ہے۔
فلٹر میں مشترکہ پیکیج کا حوالہ
# pubspec.yaml (Flutter app)
dependencies:
flutter:
sdk: flutter
firebase_core: ^3.0.0
cloud_firestore: ^5.0.0
firebase_auth: ^5.0.0
cloud_functions: ^5.0.0
shared:
path: packages/shared
فلٹر ایپس مشترکہ پیکیجز کا حوالہ دیتی ہیں۔ path: packages/sharedفلٹر پروجیکٹ کی جڑ سے متعلق راستہ۔ راستہ درج ذیل ہے: packages/shared بغیر ../ پھڑپھڑانا ایک سابقہ ہے جو فنکشن پیکجوں کے ذریعہ استعمال ہوتا ہے۔ pubspec.yaml جب تک فنکشن پروجیکٹ روٹ میں ہے۔ pubspec.yaml اندر رہتے ہیں functions/ ذیلی ڈائرکٹری۔ دونوں ڈسک پر ایک ہی فزیکل ڈائرکٹری کا حوالہ دیتے ہیں۔ یہ کلیدی بصیرت ہے۔ دو مختلف پیکیجز اور دو مختلف پیکجز ہیں۔ pubspec.yaml ایک فائل جو ایک ہی سورس کوڈ کا حوالہ دیتے ہوئے دو مختلف نقطہ نظر سے لکھی گئی ہے۔
کلاؤڈ فنکشنز میں مشترکہ منطق کا استعمال
// functions/bin/server.dart
import 'dart:convert';
import 'package:firebase_functions/firebase_functions.dart';
import 'package:google_cloud_firestore/google_cloud_firestore.dart' show FieldValue;
import 'package:shared/shared.dart';
void main(List args) async {
await fireUp(args, (firebase) {
firebase.https.onCall(
name: ApiConstants.createPostFunction,
(request, response) async {
if (request.auth == null) {
throw FirebaseFunctionsException(
code: 'unauthenticated',
message: 'You must be signed in.',
);
}
final data = request.data as Map;
final title = data['title'] as String?;
final content = data['content'] as String?;
final titleError = PostValidation.validateTitle(title);
if (titleError != null) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: titleError,
);
}
final contentError = PostValidation.validateContent(content);
if (contentError != null) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: contentError,
);
}
final ref = await firebase.adminApp
.firestore()
.collection(ApiConstants.postsCollection)
.add({
'title': title!.trim(),
'content': content!.trim(),
'authorId': request.auth!.uid,
'likeCount': 0,
'createdAt': FieldValue.serverTimestamp(),
});
return CallableResult({'postId': ref.id});
},
);
});
}
import 'package:shared/shared.dart' ایک لائن میں پورا مشترکہ پیکج حاصل کریں۔ ApiConstants.createPostFunction سٹرنگ لٹریلز کے بجائے فنکشن کے ناموں میں مشترکہ مستقل استعمال کریں تاکہ اس بات کو یقینی بنایا جا سکے کہ سرور جن ناموں کو رجسٹر کرتا ہے وہ بالکل وہی ہیں جو آپ کا لاگنگ یا مانیٹرنگ سسٹم توقع کرتا ہے۔ PostValidation.validateTitle(title) اور PostValidation.validateContent(content) پھڑپھڑانے والی شکلیں بالکل اسی طرح کی توثیق کی منطق چلاتی ہیں جیسے وہ کلائنٹ پر چلتی ہیں۔ یہاں تک کہ اگر ایک بدنیتی پر مبنی اداکار کلائنٹ کی توثیق کو نظرانداز کرتا ہے (جو ہمیشہ ممکن ہے کیونکہ کلائنٹ کوڈ ناقابل اعتماد ہے)، سرور آزادانہ طور پر وہی اصول لاگو کرے گا۔ ApiConstants.postsCollection ایک مشترکہ مجموعہ کا نام مستقل، جو اس بات کو یقینی بناتا ہے کہ فنکشن اسی مجموعہ کے راستے پر لکھتا ہے جس سے Flutter ایپ پڑھتی ہے۔
اپنی فلٹر ایپ میں مشترکہ منطق کا استعمال کریں۔
// lib/features/create_post/create_post_screen.dart
import 'package:flutter/material.dart';
import 'package:shared/shared.dart';
class CreatePostScreen extends StatefulWidget {
const CreatePostScreen({super.key});
@override
State createState() => _CreatePostScreenState();
}
class _CreatePostScreenState extends State {
final _titleController = TextEditingController();
final _contentController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('New Post')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextFormField(
controller: _titleController,
decoration: const InputDecoration(labelText: 'Title'),
validator: (value) => PostValidation.validateTitle(value),
maxLength: PostValidation.titleMaxLength,
),
const SizedBox(height: 16),
TextFormField(
controller: _contentController,
decoration: const InputDecoration(labelText: 'Content'),
validator: (value) => PostValidation.validateContent(value),
maxLength: PostValidation.contentMaxLength,
maxLines: 8,
),
],
),
),
);
}
@override
void dispose() {
_titleController.dispose();
_contentController.dispose();
super.dispose();
}
}
validator: (value) => PostValidation.validateTitle(value) مشترکہ تصدیق کنندہ کو براہ راست پاس کریں۔ TextFormFieldایس validator جائیداد فلٹر کا فارم سسٹم اس فنکشن کو اس وقت کال کرتا ہے جب صارف فارم جمع کراتا ہے، اور واپسی کی قیمت یا تو null (درست) یا ایک ایرر سٹرنگ (غلط) ہوتی ہے، جو اصول سے بالکل میل کھاتی ہے۔ PostValidation میں اسے استعمال کرتا ہوں۔ maxLength: PostValidation.titleMaxLength فیلڈز کے لیے حروف کی حدود کو ترتیب دینے کے لیے مشترکہ مستقل استعمال کریں تاکہ آپ کا UI انہی حدود کی عکاسی کرے جو توثیق نافذ کرتی ہے۔ بعد میں، جب زیادہ سے زیادہ لمبائی 120 سے 200 تک بڑھ جاتی ہے، مشترکہ پیکج میں مستقل کو اپ ڈیٹ کرنے سے فارم کے کریکٹر کاؤنٹرز اور توثیق کے قواعد خود بخود اپ ڈیٹ ہو جائیں گے جو کلائنٹ اور سرور دونوں پر ایک ہی تبدیلی کے ساتھ لاگو ہوتے ہیں۔
فن تعمیر: کس طرح پورا اسٹیک ایک ساتھ فٹ بیٹھتا ہے۔

یہ خاکہ ایک درخواست کا مکمل سفر دکھاتا ہے۔ پھڑپھڑانے والی ایپس مقامی طور پر توثیق کرنے کے لیے مشترکہ منطق کا استعمال کرتی ہیں اور پھر قابل کال فنکشنز کو کال کرتی ہیں۔ فائر بیس کا انفراسٹرکچر درخواست وصول کرتا ہے، تصدیقی ٹوکن کی تصدیق کرتا ہے، اور کلاؤڈ رن پر چلنے والی درست ڈارٹ بائنری کی درخواست کو روٹ کرتا ہے۔ ڈارٹ فنکشن اپنی توثیق کو چلانے کے لیے اسی مشترکہ منطق کا استعمال کرتا ہے اور ایڈمن SDK رسائی کا استعمال کرتے ہوئے Firestore کو لکھتا ہے۔ فلٹر کلائنٹ وہ نتائج واپس کرتا ہے جو اسے سٹرکچرڈ ڈیٹا کے طور پر موصول ہوتا ہے۔ اس مجموعی بہاؤ میں، کوڈ کے تمام ٹکڑے جو کلائنٹ اور سرور کے درمیان شیئر کیے جاسکتے ہیں شیئر کیے جاتے ہیں، اور وہ تمام ٹکڑوں کو جنہیں الگ کرنے کی ضرورت ہوتی ہے (فلٹر ویجٹس، فائربیس مینجمنٹ ٹاسک) مناسب طریقے سے الگ کردیئے جاتے ہیں۔
مکمل اسٹیک ڈارٹ پروجیکٹ کا پروجیکٹ ڈھانچہ

پراجیکٹ کی جڑ کا تین ڈائرکٹری ڈھانچہ تنظیمی اصول ہے۔ lib/ فلٹر ایپس کے لیے functions/ پسدید کے لیے packages/ ان کے درمیان مشترکہ ہر چیز کے بارے میں۔ یہ علیحدگی آپ کو فوری طور پر یہ جاننے کی اجازت دیتی ہے کہ کوڈ کا ایک ٹکڑا کہاں سے تعلق رکھتا ہے۔ کہ services/ آپ کی فلٹر ایپ کی ڈائرکٹری یہ ہے: FunctionsService اور اسی طرح کی کلاسز کو ویجیٹ میں فنکشن کال لاجک رکھنے کے لیے چالو کیا جاتا ہے۔ کہ handlers/ اندرونی ڈائریکٹری functions/lib/ یہ وہ جگہ ہے جہاں ڈومین کے ساتھ مخصوص فنکشن منطق رہتا ہے۔ server.dart صاف اور صرف رجسٹریشن پر توجہ مرکوز کریں۔
اعلی درجے کے تصورات
متعدد خصوصیات کو ترتیب دیں۔
جیسے جیسے آپ کا بیک اینڈ بڑھتا ہے، آپ اپنے تمام فنکشنز کو ایک ہی میں رجسٹر کرتے ہیں۔ fireUp کال بیکس ناکارہ ہو جاتے ہیں۔ ہینڈلر کو الگ فائل میں نکالیں اور اسے اپنے سرور انٹری پوائنٹ میں درآمد کریں۔
// functions/lib/handlers/post_handler.dart
import 'package:firebase_functions/firebase_functions.dart';
import 'package:google_cloud_firestore/google_cloud_firestore.dart' show FieldValue;
import 'package:shared/shared.dart';
void registerPostHandlers(FirebaseApp firebase) {
firebase.https.onCall(
name: ApiConstants.createPostFunction,
(request, response) async {
// handler logic
},
);
firebase.https.onCall(
name: ApiConstants.likePostFunction,
(request, response) async {
// handler logic
},
);
firebase.https.onRequest(
name: ApiConstants.getUserProfileFunction,
(request) async {
// handler logic
},
);
}
registerPostHandlers(FirebaseApp firebase) یہ ایک عمومی ٹاپ لیول فنکشن ہے جو اجازت دیتا ہے: firebase ایک آبجیکٹ بنائیں اور اسے پوسٹ سے متعلق تمام فنکشنز کو رجسٹر کرنے کے لیے استعمال کریں۔ فنکشن دستخط FirebaseApp firebase کے ذریعہ فراہم کردہ قسم کا استعمال کریں۔ firebase_functions پیرامیٹرز صحیح طریقے سے درج کیے گئے ہیں۔ یہ نقطہ نظر ہے main.dart فلٹر ایپ آپریشن: ایک واحد انٹری پوائنٹ جو مختلف کنفیگریشن ایریاز کے لیے ذمہ دار سیٹ اپ فنکشنز کو کال کرتا ہے۔
// functions/bin/server.dart
import 'package:firebase_functions/firebase_functions.dart';
import '../lib/handlers/post_handler.dart';
import '../lib/handlers/user_handler.dart';
void main(List args) async {
await fireUp(args, (firebase) {
registerPostHandlers(firebase);
registerUserHandlers(firebase);
});
}
server.dart یہ اب ایک صاف آرکیسٹریشن فائل ہے۔ ہم ہر ڈومین ہینڈلر فائل سے رجسٹریشن فنکشن درآمد کرتے ہیں اور اسے اندرونی طور پر ترتیب سے کال کرتے ہیں۔ fireUp. نیا ڈومین شامل کرنا اتنا ہی آسان ہے جتنا کہ ایک نئی ہینڈلر فائل بنانا اور اس میں لائن شامل کرنا: وہ fireUp کال بیک ہے۔ firebase چونکہ آبجیکٹ دستیاب ہے، اس لیے اسے کسی بھی رجسٹریشن فنکشن میں منتقل کیا جانا چاہیے جس کی ضرورت ہو۔
پیٹرن کو سنبھالنے میں خرابی۔
پروڈکشن کلاؤڈ فنکشنز کو مستقل اور قابل پیشن گوئی غلطی سے نمٹنے کی ضرورت ہوتی ہے۔ تمام فنکشنز میں ٹرائی کیچ بلاکس کو تقسیم کرنے کے بجائے، ایک سنٹرلائزڈ ایرر ہینڈلر کی وضاحت کریں۔
// functions/lib/utils/error_handler.dart
import 'package:firebase_functions/firebase_functions.dart';
typedef CallableHandler = Future Function(
CallableRequest request,
CallableResponse response,
);
CallableHandler withErrorHandling(CallableHandler handler) {
return (request, response) async {
try {
return await handler(request, response);
} on FirebaseFunctionsException {
rethrow;
} on ArgumentError catch (e) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: e.message,
);
} catch (e, stackTrace) {
print('Unhandled error in function: $e');
print(stackTrace);
throw FirebaseFunctionsException(
code: 'internal',
message: 'An internal error occurred. Please try again.',
);
}
};
}
typedef CallableHandler ہینڈلر کے دستخطوں کے لیے ڈارٹ فنکشن کی قسم کے عرفی نام کی وضاحت کرتا ہے۔ onCall میں اس کا منتظر ہوں۔ یہ ہے withErrorHandling آپ پورے فیچر کے دستخط کو دہرائے بغیر کہیں بھی داخل کر سکتے ہیں۔ withErrorHandling یہ ایک اعلی آرڈر کی تقریب ہے. یہ ایک ہینڈلر فنکشن لیتا ہے اور ایک نیا فنکشن لوٹاتا ہے جو اصل کو ٹرائی کیچ میں لپیٹ دیتا ہے۔ on FirebaseFunctionsException { rethrow; } ساختی غلطیاں جو جان بوجھ کر ہینڈلر کے ذریعہ پھینکی جاتی ہیں بغیر کسی تبدیلی کے گزر جاتی ہیں کیونکہ وہ کلائنٹ کے لیے پہلے سے ہی درست شکل میں ہیں۔ on ArgumentError catch (e) ڈارٹ کی ہمت کو تبدیل کریں۔ ArgumentError (عام طور پر توثیق کوڈ کی وجہ سے) FirebaseFunctionsException کے ساتھ invalid-argument کوڈ جسے کلائنٹ سمجھ سکتے ہیں۔ حتمی catch (e, stackTrace) یہ اندرونی طور پر مکمل خرابی کو لاگو کرنے کے لیے بغیر ہینڈل شدہ مستثنیات کے لیے حفاظتی جال کے طور پر اسٹیک ٹریس کا استعمال کرتا ہے، جبکہ کلائنٹ کو ایک صاف شدہ پیغام بھی واپس کرتا ہے جو اندرونی خرابی کے بارے میں کچھ بھی ظاہر نہیں کرتا ہے۔
firebase.https.onCall(
name: 'createPost',
withErrorHandling((request, response) async {
if (request.auth == null) {
throw FirebaseFunctionsException(
code: 'unauthenticated',
message: 'Authentication required.',
);
}
return CallableResult({'success': true});
}),
);
withErrorHandling(...) رجسٹر کرتے وقت ہینڈلر کو لپیٹ دیتا ہے۔ تیسری پوزیشن کی دلیل onCall (ہینڈلر فنکشن) کو درج ذیل ریٹرن ویلیو سے بدل دیا گیا ہے۔ withErrorHandlingیہ خود صحیح دستخط کے ساتھ ایک فنکشن ہے۔ اندرونی ہینڈلر کا اپنا ٹرائی کیچ بلاک نہیں ہے۔ withErrorHandling تمام خرابی کے منظرناموں کا احاطہ کرتا ہے۔
ڈارٹ کلاؤڈ فنکشنل ٹیسٹنگ
ڈارٹ میں لکھے گئے کلاؤڈ فنکشنز سادہ ڈارٹ کوڈ ہیں۔ اس کا مطلب یہ ہے کہ یہ معیاری ڈارٹ ٹیسٹنگ ٹولز کا استعمال کرتے ہوئے مکمل طور پر قابل آزمائش ہے۔ آپ ہینڈلر کے اندر موجود کاروباری منطق کو بغیر کسی Firebase کے انحصار کے خالص فنکشن میں نکال سکتے ہیں اور پھر یونٹ براہ راست اس کی جانچ کر سکتے ہیں۔
// functions/lib/handlers/post_logic.dart
import 'package:shared/shared.dart';
PostInput validateCreatePostRequest(Map data) {
final title = data['title'] as String?;
final content = data['content'] as String?;
final titleError = PostValidation.validateTitle(title);
if (titleError != null) throw ArgumentError(titleError);
final contentError = PostValidation.validateContent(content);
if (contentError != null) throw ArgumentError(contentError);
return PostInput(
title: title!.trim(),
content: content!.trim(),
);
}
class PostInput {
final String title;
final String content;
const PostInput({required this.title, required this.content});
}
validateCreatePostRequest ایک خالص فعل ہے. Map اور ان میں سے ایک ہے۔ PostInput یا پھینک دو۔ ArgumentError. کوئی Firebase انحصار، غیر مطابقت پذیر کالز، یا ضمنی اثرات۔ یہ ایک ہی ٹیسٹ کی اجازت دیتا ہے۔ dart test کمانڈ کا استعمال کرتے ہوئے آپ کو Firebase ایمولیٹر کی ضرورت نہیں ہے۔ PostInput ایک سادہ قدر کی کلاس جو توثیق شدہ اور کٹے ہوئے ان پٹ کو پاس کرتی ہے۔ خام نقشے کے بجائے ٹائپ شدہ نتیجہ واپس کرنا اس بات کو یقینی بناتا ہے کہ کال کرنے والے کو درست ڈیٹا اس فارمیٹ میں ملے جس کا مرتب کرنے والا اندازہ لگا سکتا ہے۔
// functions/test/post_logic_test.dart
import 'package:test/test.dart';
import '../lib/handlers/post_logic.dart';
void main() {
group('validateCreatePostRequest', () {
test('returns valid PostInput for correct data', () {
final result = validateCreatePostRequest({
'title': 'Valid Title',
'content': 'This is valid post content.',
});
expect(result.title, equals('Valid Title'));
expect(result.content, equals('This is valid post content.'));
});
test('throws ArgumentError when title is empty', () {
expect(
() => validateCreatePostRequest({'title': '', 'content': 'Content'}),
throwsA(isA()),
);
});
test('throws ArgumentError when title exceeds max length', () {
final longTitle="A" * 200;
expect(
() => validateCreatePostRequest({
'title': longTitle,
'content': 'Content',
}),
throwsA(isA()),
);
});
test('trims whitespace from title and content', () {
final result = validateCreatePostRequest({
'title': ' Padded Title ',
'content': ' Padded content. ',
});
expect(result.title, equals('Padded Title'));
expect(result.content, equals('Padded content.'));
});
});
}
group('validateCreatePostRequest', ...) منظم آؤٹ پٹ تیار کرنے کے لیے مشترکہ لیبلز میں متعلقہ ٹیسٹوں کو گروپ کریں جو غلطیوں کو تلاش کرنا آسان بناتا ہے۔ ہر ایک test(...) کال ایک مخصوص کارروائی کو انجام دیتی ہے: ایک خوشگوار راستہ، ایک خالی ٹائٹل کیس، ایک بڑا ٹائٹل کیس، یا وائٹ اسپیس ٹرمنگ کیس۔ expect(result.title, equals('Valid Title')) دعویٰ یہ جانچنے کے بارے میں ہے کہ آیا اصل قدر متوقع قدر سے میل کھاتی ہے۔ throwsA(isA ایک میچر جو صرف اس وقت پہنچایا جاتا ہے جب کال ایبل کے ذریعے پھینکا جاتا ہے۔ ArgumentErrorیہ ایک معاہدہ ہے۔ validateCreatePostRequest غلط ان پٹ کی وضاحت کرتا ہے۔ 'A' * 200 200 کریکٹر سٹرنگ بنانے کے لیے ڈارٹ سٹرنگ کی تکرار۔ titleMaxLength مشترکہ پیکیج میں بیان کردہ 120 میں سے
cd functions
dart test
فنکشنل ٹیسٹ چلانے کے لیے Firebase ایمولیٹر یا نیٹ ورک تک رسائی کی ضرورت نہیں ہے، اور اس کے لیے Dart SDK کو انسٹال کرنے کے علاوہ کسی خاص سیٹ اپ کی ضرورت نہیں ہے۔ ٹیسٹ ملی سیکنڈ میں مکمل ہوتا ہے۔
cd packages/shared
dart test
مشترکہ پیکیج ٹیسٹ یکساں طور پر چلتے ہیں۔ دونوں کمانڈ معیاری استعمال کرتے ہیں۔ dart test رنر بار بار ختم ہونے والی تمام فائلوں کو تلاش کرتا ہے اور اس پر عمل درآمد کرتا ہے۔ _test.dart پر test/ ڈائریکٹری
فیچر کنفیگریشن کے اختیارات
دونوں onRequest اور onCall رن ٹائم رویے کو کنٹرول کرنے کے لیے آپشن آبجیکٹ کو قبول کرتا ہے۔
firebase.https.onRequest(
name: 'highTrafficEndpoint',
options: const HttpsOptions(
cors: Cors(['https://yourapp.com']),
minInstances: 1,
maxInstances: 10,
concurrency: 80,
memory: Memory.mb512,
timeoutSeconds: 120,
region: 'europe-west1',
),
(request) async {
return Response.ok('Hello from a configured function!');
},
);
minInstances: 1 اس خصوصیت کے لئے سرد آغاز اس خصوصیت کی ایک مثال کو ہر وقت گرم رکھنے سے مکمل طور پر ختم ہوجاتا ہے۔ منفی پہلو یہ ہے کہ آپ کو ایک بار مسلسل چلتے رہنے کے لیے بل دیا جاتا ہے، چاہے کوئی درخواستیں نہ آئیں۔ اس خصوصیت کو صرف ان خصوصیات کے لیے استعمال کریں جہاں کولڈ اسٹارٹ لیٹنسی واقعی ناقابل قبول ہو، جیسے کہ صارف کے براہ راست تعامل کے ساتھ حقیقی وقت کی خصوصیات۔ maxInstances: 10 ہم آہنگی کی مثالوں کی تعداد کو 10 تک محدود کریں۔ یہ ٹریفک میں اچانک اضافے کو آپ کے فنکشن کو سینکڑوں مثالوں تک بڑھانے سے روکتا ہے، بلنگ اور ڈاون اسٹریم سروسز (جیسے ڈیٹا بیس) دونوں کی حفاظت کرتا ہے جو کہ اچانک زیادہ کنکرنسی سے اوورلوڈ ہو سکتی ہیں۔ concurrency: 80 کلاؤڈ رن کو بتاتا ہے کہ ایک مثال کتنی سمورتی درخواستوں کو سنبھالے گی۔ ڈارٹ کے غیر مطابقت پذیر ماڈل کو Node.js سے اونچا سیٹ کیا جا سکتا ہے کیونکہ یہ بغیر تھریڈز کے سمورتی I/O پابند درخواستوں کو مؤثر طریقے سے ہینڈل کرتا ہے۔ memory: Memory.mb512 ہر فنکشن مثال کے لیے 512 MB RAM مختص کریں۔ اس قدر کو میموری سے متعلق کاموں کے لیے بڑھائیں جیسے امیج پروسیسنگ یا بڑے ڈیٹا سیٹس کو لوڈ کرنا۔ سی پی یو ایلوکیشن میموری کے ساتھ لکیری طور پر ترازو کرتا ہے، لہذا میموری میں اضافہ پروسیسنگ پاور کو بھی بڑھاتا ہے۔ timeoutSeconds: 120 کلاؤڈ رن کی درخواست کو ختم کرنے سے پہلے درخواست کے چلنے کا زیادہ سے زیادہ وقت مقرر کرتا ہے۔ طویل عرصے سے چلنے والے کاموں کے لیے، اس قدر میں اضافہ کریں۔ region: 'europe-west1' ہم نے اس خصوصیت کو بیلجیم میں Google ڈیٹا سینٹرز پر تعینات کیا تاکہ یورپی صارفین کے لیے تاخیر کو کم کیا جا سکے۔ پہلے سے طے شدہ طور پر، افعال کو تعینات کیا جاتا ہے: us-central1.
پیداوار کے استعمال کے لیے بہترین طریقے
کسی تجربے کو بطور تجربہ سمجھیں۔
سب سے اہم طریقہ یہ ہے کہ پروڈکشن کے استعمال کو فیچر کی حقیقی پختگی کے ساتھ ہم آہنگ کیا جائے۔ ڈارٹ کلاؤڈ کی خصوصیات تجرباتی ہیں۔ اس کا مطلب پیداوار کے فیصلوں کے بارے میں دو مخصوص چیزیں ہیں۔
سب سے پہلے، API بغیر اطلاع کے بدل سکتا ہے۔ مستقبل کی Firebase CLI اپ ڈیٹس کی وجہ سے یہ طریقہ تبدیل ہو سکتا ہے۔ fireUp یہ کیسے کام کرتا ہے، فیچر کو کیسے رجسٹر کیا جائے یا ایڈمن SDK تک کیسے رسائی حاصل کی جائے۔ ڈارٹ فیچرز استعمال کرنے والے پروجیکٹس میں CLI کو اپ ڈیٹ کرنے سے پہلے، تبدیلی لاگ کو پڑھیں اور اسٹیجنگ ماحول میں ٹیسٹ کریں۔ اپنے پیداواری ٹولز کو آنکھیں بند کرکے اپ ڈیٹ نہ کریں۔
دوسرا، کچھ چیزیں ابھی تک کام نہیں کرتی ہیں۔ پس منظر کا محرک، نام کی بنیاد پر httpsCallable موجودہ ریلیز میں کال اور فائر بیس کنسول ڈسپلے دونوں خالی ہیں۔ تعیناتی کے دوران ان حدود کو دریافت کرنے کے بجائے، ان کے لیے شروع سے ڈیزائن کریں۔
ہینڈلرز کو پتلا رکھیں اور منطق کا اشتراک کریں۔
رجسٹرڈ ہینڈلر firebase.https.onCall یا firebase.https.onRequest آپ کو کم سے کم کام کرنا چاہیے۔ یہ درخواست کی تصدیق کرتا ہے، ان پٹ کو نکالتا ہے، ایک خالص فنکشن کو کال کرتا ہے جو اصل کام کرتا ہے، اور نتیجہ واپس کرتا ہے۔ خالص افعال فنکشن لائبریریوں یا مشترکہ پیکجوں سے تعلق رکھتے ہیں۔ یہ ڈھانچہ آپ کو فائربیس ماحول کے بغیر اپنی منطق کو جانچنے کی اجازت دیتا ہے اور اگر آپ کی فلٹر ایپ کے لیے ضرورت ہو تو بعد میں آپ کو منطق کو آسانی سے مشترکہ پیکیج میں منتقل کرنے کی اجازت دیتا ہے۔
تمام ٹائم اسٹیمپ کے لیے FieldValue.serverTimestamp() استعمال کریں۔
کلائنٹ سے کبھی بھی ٹائم اسٹیمپ نہ بھیجیں اور نہ ہی فنکشن کوڈ میں ٹائم اسٹیمپ بنائیں۔ DateTime.now(). سرور ٹائم اسٹیمپ فائر اسٹور کے ذریعہ تحریری وقت پر سیٹ کیے جاتے ہیں اور کال کرنے والے کی گھڑی سے قطع نظر درست ہونے کی ضمانت دی جاتی ہے۔ اگر صارف کی ڈیوائس کی گھڑی غلط ہے، تو کلائنٹ کی طرف سے تیار کردہ ٹائم اسٹیمپ غلط ہو سکتا ہے۔ فنکشن بنائیں DateTime.now() ٹائم اسٹیمپ درست ہے، لیکن فنکشن ایگزیکیوشن اور فائر اسٹور رائٹ کمٹ کے درمیان وقت کا تھوڑا سا فرق یاد کرتا ہے۔
بامعنی طور پر ریکارڈ کریں، لیکن اسے زیادہ نہ کریں۔
کلاؤڈ فنکشن لاگز گوگل کلاؤڈ کنسول اور کلاؤڈ رن لاگز میں ظاہر ہوتے ہیں۔ print() ڈارٹ فنکشنز ان لاگز پر لکھتے ہیں۔ لاگ ان ایونٹس جو پیداواری مسائل کو ڈیبگ کرنے کے لیے کارآمد ہیں: کارکردگی سے متعلقہ ایونٹس جیسے کہ ان پٹ شکلوں کے ساتھ فنکشن کالز (حساس ڈیٹا نہیں)، نتائج کی شکلوں کے ساتھ کامیاب تکمیل، مکمل خامیوں اور اسٹیک ٹریس کے ساتھ خرابیاں، اور بیرونی API کالز۔ ہر عمل درآمد قطار یا ہر ڈیٹا کی تبدیلی کو لاگ ان نہ کریں۔ یہ آپ کے لاگز کو اوور فلو کر دے گا اور اصل غلطی کو تلاش کرنا مشکل بنا دے گا۔
شرح محدود اور بنیادی تصدیق
کوئی بھی کلاؤڈ فنکشن جو انٹرنیٹ پر قابل رسائی ہے اسے ممکنہ طور پر کوئی بھی شخص کال کر سکتا ہے جو اس کا URL دریافت کرتا ہے۔ کال کے قابل فنکشنز خود بخود Firebase کی توثیق کرتے ہیں، HTTP فنکشنز ایسا نہیں کرتے۔ ہر onRequest اگر آپ کے فنکشن کو تصدیق کی ضرورت ہے، تو واضح طور پر ID ٹوکن کو چیک کریں۔ تمام خصوصیات کے لیے، قطع نظر اس کی قسم، ہم تجویز کرتے ہیں کہ ریلیز سے پہلے فی صارف کی شرح کو محدود کریں تاکہ حادثاتی لوپس اور جان بوجھ کر غلط استعمال کو روکا جا سکے۔
ڈارٹ کلاؤڈ کی خصوصیات کب اور کب استعمال نہ کریں۔
جہاں ڈارٹ کلاؤڈ کی خصوصیات حقیقی قدر میں اضافہ کرتی ہیں۔
ڈارٹ کلاؤڈ فنکشنز فلٹر فرسٹ ٹیموں کے لیے سب سے زیادہ قیمتی ہیں جو ڈارٹ میں سیاق و سباق کی تبدیلی کے بغیر بیک اینڈ لاجک لکھنا چاہتی ہیں۔ یہ وہ جگہ ہے جہاں مشترکہ پیکیج پیٹرن کی سب سے بڑی تعمیراتی قدر ہے۔ جب بھی کلائنٹ اور سرور دونوں کے لیے توثیق کے قوانین، ڈیٹا ماڈلز، مستقل یا یوٹیلیٹی منطق کی ضرورت ہوتی ہے، دونوں طرف سے اس کوڈ کو ایک ہی ڈارٹ پیکج میں شیئر کرنے سے ڈیٹا کنٹریکٹ کی خرابیوں کی ایک پوری قسم ختم ہوجاتی ہے۔
ہلکا پھلکا I/O بائنڈنگ API منطق موزوں ہے۔ ڈارٹ کا غیر مطابقت پذیر ماڈل کام کے بوجھ کے لیے کارآمد ہے جو اپنا زیادہ تر وقت Firestore کے سوالات، ایکسٹرنل API کالز، یا ضرورت سے زیادہ گنتی کرنے کے بجائے نیٹ ورک کے دیگر آپریشنز کے انتظار میں صرف کرتے ہیں۔ Firestore سے کچھ دستاویزات کو پڑھنے، کاروباری منطق کو لاگو کرنے، اور نتائج کو واپس لکھنے کی صلاحیت بالکل اسی قسم کے کام کا بوجھ ہے جسے Dart اچھی طرح سے سنبھالتا ہے۔
موبائل بیک اینڈ فار فرنٹ اینڈ پیٹرن قدرتی استعمال کا معاملہ ہے۔ متعدد فائر اسٹور کلیکشنز سے ڈیٹا کو ایک مخصوص اسکرین کے مطابق ایک ہی جواب میں جمع کرنے کی اہلیت، تحریری کارروائیوں کو انجام دینے کے لیے جس میں متعدد دستاویزات میں ایٹم اپ ڈیٹ کی ضرورت ہوتی ہے، اور ایسے ریکارڈ بنانے یا اپ ڈیٹ کرنے کے لیے ایڈمنسٹریٹر تک رسائی کی ضرورت ہوتی ہے جو کلائنٹس کو براہ راست ترمیم کرنے کے قابل نہیں ہونا چاہیے۔
جب موجودہ ڈارٹ کلاؤڈ کی خصوصیات خراب انتخاب ہیں۔
پس منظر کے محرکات فی الحال قابل تعینات نہیں ہیں۔ اگر آپ کا آرکیٹیکچر فائر اسٹور دستاویز کے بننے یا اپ ڈیٹ ہونے پر چلنے والے فنکشنز پر انحصار کرتا ہے، جب صارف سائن اپ کرتا ہے، شیڈول پر، یا پب/سب میسج کے جواب میں، آپ فی الحال ان فنکشنز کے لیے ڈارٹ استعمال نہیں کر سکتے۔ آپ کو Node.js یا Python میں لکھنا پڑے گا اور مستقبل کی ریلیز میں بیک گراؤنڈ ٹرگر سپورٹ آنے کا انتظار کرنا پڑے گا۔
تجرباتی ٹولز استعمال کرنے سے پہلے پیداوار کے لیے اہم انفراسٹرکچر کا بغور جائزہ لینا چاہیے۔ اگر کسی فنکشنل ناکامی کے نتیجے میں ڈیٹا کا نقصان، مالیاتی ناکامی، یا صارف کے اہم اثرات ہوتے ہیں، تو ڈارٹ سپورٹ کا تجرباتی لیبل ایک معنی خیز خطرہ ہے۔ APIs تبدیل ہو سکتے ہیں اور طرز عمل تبدیل ہو سکتا ہے، اور تجرباتی خصوصیات میں اہم پروڈکشن بگز کو فوری طور پر حل کرنے کی Firebase ٹیم کی قابلیت مستحکم خصوصیات کے لیے اس کی وابستگی سے مختلف ہے۔
اگر آپ کے پاس کام کے بہت سے کام کے بوجھ ہیں جن کے لیے بہترین کارکردگی کی خصوصیات کی ضرورت ہوتی ہے، تو آپ ڈارٹ سے کمٹمنٹ کرنے سے پہلے حقیقی ٹریفک کے ساتھ جانچ سے فائدہ اٹھا سکتے ہیں۔ اگرچہ ڈارٹ فیچرز کے لیے کارکردگی کی کہانی (بہترین کولڈ اسٹارٹس، موثر غیر مطابقت پذیر I/O پروسیسنگ) تھیوری میں مضبوط ہے، لیکن پروڈکشن ٹریفک ایسے ایج کیسز کو ظاہر کر سکتی ہے جو مقامی ٹیسٹنگ میں نہیں دیکھے جا سکتے ہیں۔
عام غلطیاں
تجرباتی پرچم بھول گئے۔
سب سے عام ابتدائی مسئلہ چل رہا ہے۔ firebase init functions میں ڈارٹ کو زبان کے آپشن کے طور پر نہیں دیکھ رہا ہوں۔ اصلاح ہمیشہ ایک جیسی ہوتی ہے۔ پھانسی firebase experiments:enable dartfunctions اسے پہلے اور پھر چلائیں۔ firebase init functions. ڈارٹ کے بطور اختیار دستیاب ہونے کے لیے، آپ کو پہلے فائر بیس CLI میں تجرباتی جھنڈا سیٹ کرنا ہوگا۔
pubspec.yaml میں متعلقہ راستے کا غلط استعمال
مشترکہ پیکجوں کا حوالہ دونوں پیکجوں میں رشتہ دار راستے پر انحصار کرتے ہوئے دیا جاتا ہے۔ functions/pubspec.yaml اور فلٹر ایپ pubspec.yaml. اگر رشتہ دار راستہ غلط ہے (یا تو اس وجہ سے کہ فولڈر کا ڈھانچہ کوڈ بیس میں توقع سے مختلف ہے یا اس وجہ سے کہ پیکج کو منتقل کر دیا گیا ہے)، فنکشن کمپائلیشن اور فلٹر بلڈ دونوں پیکیج ریزولوشن کی خرابی کے ساتھ ناکام ہو جائیں گے۔ دوڑ کر راستہ چیک کریں: dart pub get آپ کی فنکشن ڈائرکٹری سے تعینات کرنے سے پہلے تصدیق کریں کہ یہ غلطیوں کے بغیر حل ہو جاتا ہے۔
httpsCallable نام کی پابندیوں کو سنبھالنا بھول جانا
موجودہ ریلیز میں سب سے عام انٹیگریشن بگ ڈارٹ فنکشنز کو کال کر رہا ہے۔ FirebaseFunctions.instance.httpsCallable('functionName') میں متجسس ہوں کہ یہ نہ ملنے والی غلطی کیوں لوٹاتا ہے۔ موجودہ ریلیز ڈارٹ خصوصیات کے لیے نام پر مبنی ریزولوشن کو سپورٹ نہیں کرتی ہے۔ آپ کو استعمال کرنا چاہئے httpsCallableFromURL براہ کرم کلاؤڈ رن کا پورا URL استعمال کریں۔ تعیناتی آؤٹ پٹ کا URL محفوظ کریں اور اسے اپنے فلٹر کوڈ میں واضح طور پر استعمال کریں۔
Firebase کنسول میں اپنا فنکشن تلاش کریں۔
اپنے ڈارٹ فنکشن کو تعینات کرنے کے بعد، جب آپ Firebase کنسول کے فنکشنز سیکشن کو کھولتے ہیں، تو شاید آپ کو کچھ نظر نہیں آتا جب تک کہ آپ کو معلوم نہ ہو کہ آیا یہ متوقع رویہ ہے۔ ڈارٹ فنکشنز کو کلاؤڈ رن پر تعینات کیا جاتا ہے اور وہ فائر بیس کنسول پر نہیں بلکہ گوگل کلاؤڈ کنسول میں کلاؤڈ رن فنکشنز کے صفحہ پر ظاہر ہوتے ہیں۔ تجرباتی ریلیز میں یہ ایک معلوم خلا ہے اور فیچر کے عام دستیابی تک پہنچنے کے بعد اسے دور کیا جائے گا۔
مشترکہ پیکجوں میں Firebase انحصار شامل کریں۔
مشترکہ پیکجوں کو Firebase اور Flutter پیکجز سے آزاد رہنا چاہیے۔ شامل کرنا firebase_functions یا cloud_firestore مشترکہ پیکجوں پر انحصار بنیادی فن تعمیر کو توڑ دیتا ہے۔ مشترکہ پیکجز یا تو آپ کے فلٹر ایپ میں سرور سائیڈ فائربیس انحصار درآمد کرتے ہیں یا کلائنٹ سائیڈ فائربیس انحصار کو فنکشنز میں درآمد کرتے ہیں، جس کے نتیجے میں ورژن میں تنازعات اور تالیف کی خرابیاں پیدا ہوتی ہیں۔ مشترکہ پیکیج میں صرف خالص ڈارٹ منطق اور ماڈل شامل ہیں۔ فائربیس کے تعاملات فنکشن پیکیج اور فلٹر ایپ میں الگ الگ ہوتے ہیں، یہ دونوں مشترکہ پیکجز درآمد کرتے ہیں۔
تمام کاروباری منطق کو براہ راست اندر رکھیں onCall یا onRequest کال بیکس آپ کو فائر بیس ایمولیٹر کو چلائے بغیر یونٹ ٹیسٹ کرنے سے روکتی ہیں۔ ڈارٹ کی طاقت اس کی آزمائش ہے۔ فنکشن لائبریری یا مشترکہ پیکج میں خالص افعال میں توثیق، تبدیلی، اور کاروباری منطق نکالیں۔ ان خالص خصوصیات کی جانچ کریں: dart test یہ Firebase انفراسٹرکچر کے بغیر ممکن ہے۔ اپنے سین لیئر کے لیے ہینڈلر کال بیکس کو شیڈول کریں جو Firebase ان پٹس اور آؤٹ پٹس کو ان کی خالص منطق سے جوڑتا ہے۔
منی اینڈ ٹو اینڈ مثال
آئیے ایک مکمل طور پر کام کرنے والی، فل اسٹیک ڈارٹ ایپلی کیشن بنائیں، جس میں ایک مشترکہ ماڈل، مشترکہ توثیق، فائر اسٹور پر لکھنے والا ڈارٹ کلاؤڈ فنکشن، اور فنکشن کو کال کرنے والی فلٹر اسکرین کے ساتھ پوسٹ تخلیق فنکشن شامل ہے۔ یہ ہینڈ بک کے تمام تصورات کو ایک قابل عمل پروجیکٹ میں ضم کرتا ہے۔
مشترکہ پیکج
// packages/shared/lib/src/models/post.dart
class Post {
final String id;
final String title;
final String content;
final String authorId;
final int likeCount;
const Post({
required this.id,
required this.title,
required this.content,
required this.authorId,
required this.likeCount,
});
factory Post.fromMap(String id, Map data) {
return Post(
id: id,
title: data['title'] as String? ?? '',
content: data['content'] as String? ?? '',
authorId: data['authorId'] as String? ?? '',
likeCount: data['likeCount'] as int? ?? 0,
);
}
Map toMap() => {
'title': title,
'content': content,
'authorId': authorId,
'likeCount': likeCount,
};
}
Post.fromMap دستاویز کی ID اور دستاویز کا فیلڈ میپ، جسے Firestore دستاویز کے ڈیٹا سے باہر اسٹور کرتا ہے، دونوں کو لے کر مکمل طور پر آباد ہوتا ہے۔ Post مثال کہ as String? ?? '' پیٹرن ایک محفوظ کاسٹ ہے جس کے بعد ایک کالعدم متبادل ہے۔ اگر کوئی فیلڈ غائب یا null ہے تو، null dereference error کو بڑھانے کے بجائے ایک خالی سٹرنگ استعمال کی جاتی ہے۔ toMap() سیریلائزیشن Post کی طرف سے Map جان بوجھ کر خارج کر دیا گیا، اسے Firestore پر لکھنے کے لیے موزوں بنا دیا گیا۔ id اس کی وجہ یہ ہے کہ Firestore دستاویز کے باڈی سے باہر دستاویز IDs تیار اور اسٹور کرتا ہے۔ کہ likeCount جب کوئی نئی پوسٹ بنتی ہے، تو یہ 0 سے شروع ہوتی ہے اور سرور کی طرف بڑھنے والے آپریشن کے ذریعے اپ ڈیٹ ہوتی ہے۔
// packages/shared/lib/src/validation/post_validation.dart
class PostValidation {
static const int titleMaxLength = 120;
static const int contentMaxLength = 5000;
static String? validateTitle(String? value) {
if (value == null || value.trim().isEmpty) return 'Title is required.';
if (value.trim().length > titleMaxLength) {
return 'Title cannot exceed $titleMaxLength characters.';
}
return null;
}
static String? validateContent(String? value) {
if (value == null || value.trim().isEmpty) return 'Content is required.';
if (value.trim().length > contentMaxLength) {
return 'Content cannot exceed $contentMaxLength characters.';
}
return null;
}
}
یہ ایک آسان ورژن ہے۔ PostValidation آخر سے آخر تک مثالوں کے لیے استعمال کیا جاتا ہے۔ دونوں طریقے توثیق کنٹریکٹ کی پیروی کرتے ہیں۔ null اس کا مطلب جائز ہے۔ String اس کا مطلب ہے کہ یہ دی گئی وجہ سے باطل ہے۔ چیکس کا حکم سب سے عام غلطیوں (خالی ان پٹ) سے لے کر زیادہ مخصوص خرابیوں (بہت طویل) تک دیا جاتا ہے۔ یہ منطقی اور موثر ہے کیونکہ طوالت کی جانچ کے چلنے سے پہلے خالی چیک شارٹ سرکٹ ہوتا ہے۔
// packages/shared/lib/src/constants/api_constants.dart
class ApiConstants {
static const String createPost="createPost";
static const String postsCollection = 'posts';
}
آخر سے آخر تک مثال میں، ApiConstants اس کو اس فنکشن کے لیے درکار دو کنسٹینٹس تک چھوٹا کیا جاتا ہے: فنکشن کا نام اور مجموعہ کا نام۔ یہ مثال کو مرکوز رکھے گا۔ ایک حقیقی ایپلی کیشن میں، یہ کلاس پوری ایپ میں استعمال ہونے والے تمام فنکشن اور مجموعہ کے ناموں پر مشتمل ہو جائے گی۔
// packages/shared/lib/shared.dart
export 'src/models/post.dart';
export 'src/validation/post_validation.dart';
export 'src/constants/api_constants.dart';
بیرل فائل تینوں ماڈیولز کو برآمد کرتی ہے۔ اسٹیک کے دونوں طرف کی تمام فائلیں درآمد کی جا رہی ہیں۔ package:shared/shared.dart فوری رسائی حاصل کریں۔ Post، PostValidationاور ApiConstants آپ کو یہ جاننے کی بھی ضرورت نہیں ہے کہ یہ کس سب ڈائرکٹری میں رہتی ہے۔
بادل کی خصوصیات
// functions/bin/server.dart
import 'dart:convert';
import 'package:firebase_functions/firebase_functions.dart';
import 'package:google_cloud_firestore/google_cloud_firestore.dart' show FieldValue;
import 'package:shared/shared.dart';
void main(List args) async {
await fireUp(args, (firebase) {
firebase.https.onCall(
name: ApiConstants.createPost,
options: const CallableOptions(cors: Cors(['*'])),
(request, response) async {
if (request.auth == null) {
throw FirebaseFunctionsException(
code: 'unauthenticated',
message: 'You must be signed in to create a post.',
);
}
final uid = request.auth!.uid;
final data = request.data as Map? ?? {};
final title = data['title'] as String?;
final content = data['content'] as String?;
final titleError = PostValidation.validateTitle(title);
if (titleError != null) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: titleError,
);
}
final contentError = PostValidation.validateContent(content);
if (contentError != null) {
throw FirebaseFunctionsException(
code: 'invalid-argument',
message: contentError,
);
}
try {
final ref = await firebase.adminApp
.firestore()
.collection(ApiConstants.postsCollection)
.add({
'title': title!.trim(),
'content': content!.trim(),
'authorId': uid,
'likeCount': 0,
'createdAt': FieldValue.serverTimestamp(),
});
return CallableResult({
'postId': ref.id,
'success': true,
});
} catch (e) {
print('Error writing post to Firestore: $e');
throw FirebaseFunctionsException(
code: 'internal',
message: 'Failed to create post. Please try again.',
);
}
},
);
});
}
final data = request.data as Map ایسے معاملات کو محفوظ طریقے سے ہینڈل کرتا ہے جہاں کلائنٹ خالی نقشے پر واپس گر کر، انفرادی فیلڈز کو نکالنے سے پہلے null dereferences کو روک کر ایک null body بھیجتا ہے۔ کہ ! کو title!.trim() اور content!.trim() آپ کوڈ میں اس مقام پر محفوظ ہیں کیونکہ اوپر کی توثیق پہلے سے ہی اس بات کو یقینی بناتی ہے کہ دونوں قدریں غیر کالعدم اور غیر خالی ہیں۔ فائر اسٹور رائٹ کے لیے کوشش/کیچ حتمی حفاظتی جال ہے۔ اگر ایڈمن SDK تحریر کسی بھی وجہ سے ناکام ہو جاتی ہے (نیٹ ورک کے مسائل، فائر اسٹور کوٹہ، غیر متوقع خرابیاں)، فنکشن اسے پکڑتا ہے اور مکمل داخلی خرابی کو درج ذیل لاگ کرتا ہے: print (کلاؤڈ رن لاگز میں ریکارڈ کیا گیا) حذف کر دیا گیا۔ 'internal' کلائنٹ پر ایک خرابی واقع ہوئی ہے جس میں ناکامی کی وجہ کے بارے میں کچھ نہیں کہا گیا ہے۔
فلٹر ایپ
// lib/services/functions_service.dart
import 'package:cloud_functions/cloud_functions.dart';
class FunctionsService {
static const String _createPostUrl="https://createpost-REPLACE-WITH-YOUR-HASH.a.run.app";
Future createPost({
required String title,
required String content,
}) async {
try {
final callable = FirebaseFunctions.instance
.httpsCallableFromURL(_createPostUrl);
final result = await callable.call({'title': title, 'content': content});
return result.data['postId'] as String;
} on FirebaseFunctionsException catch (e) {
throw _mapError(e);
}
}
Exception _mapError(FirebaseFunctionsException e) {
switch (e.code) {
case 'unauthenticated':
return Exception('Please sign in to continue.');
case 'invalid-argument':
return Exception(e.message ?? 'Invalid input.');
default:
return Exception('Something went wrong. Please try again.');
}
}
}
FunctionsService یہ کال ایبل فنکشن کال کے گرد ایک پتلا ریپر ہے۔ آپ کی واحد ذمہ داری یہ ہے کہ درست یو آر ایل کے ساتھ کال ایبل کی تعمیر کریں، ڈیٹا کو پاس کریں، نتائج کو نکالیں، اور ڈومین کے استثنیٰ کے لیے سٹرکچرڈ سرور کی غلطیوں کا نقشہ بنائیں۔ _mapError ترجمہ FirebaseFunctionsException ایک ایسی چیز جو Firebase سے متعلقہ کوڈ کو ریگولر کوڈ میں منتقل کرتی ہے۔ Exception ایک ایسی چیز جس میں صارف دوست پیغام ہو۔ یہ بلاک یا ویجیٹ کی پرت سے Firebase کی قسموں کو خارج کر دیتا ہے، جس سے Firebase SDK کا پابند ہوتا ہے جس کی جانچ یا تبدیل کرنا مشکل ہوتا ہے۔
// lib/features/create_post/create_post_screen.dart
import 'package:flutter/material.dart';
import 'package:shared/shared.dart';
import '../../services/functions_service.dart';
class CreatePostScreen extends StatefulWidget {
const CreatePostScreen({super.key});
@override
State createState() => _CreatePostScreenState();
}
class _CreatePostScreenState extends State {
final _formKey = GlobalKey();
final _titleController = TextEditingController();
final _contentController = TextEditingController();
final _service = FunctionsService();
bool _isSubmitting = false;
String? _errorMessage;
@override
void dispose() {
_titleController.dispose();
_contentController.dispose();
super.dispose();
}
Future _submit() async {
if (!(_formKey.currentState?.validate() ?? false)) return;
setState(() {
_isSubmitting = true;
_errorMessage = null;
});
try {
final postId = await _service.createPost(
title: _titleController.text,
content: _contentController.text,
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Post created successfully! ID: $postId')),
);
Navigator.of(context).pop();
} catch (e) {
setState(() => _errorMessage = e.toString());
} finally {
if (mounted) setState(() => _isSubmitting = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('New Post')),
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
if (_errorMessage != null)
Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Text(
_errorMessage!,
style: TextStyle(color: Colors.red.shade800),
),
),
TextFormField(
controller: _titleController,
decoration: InputDecoration(
labelText: 'Title',
hintText: 'What is your post about?',
counterText:
'({_titleController.text.length}/){PostValidation.titleMaxLength}',
),
maxLength: PostValidation.titleMaxLength,
validator: (value) => PostValidation.validateTitle(value),
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 16),
TextFormField(
controller: _contentController,
decoration: InputDecoration(
labelText: 'Content',
hintText: 'Write your post here...',
counterText:
'({_contentController.text.length}/){PostValidation.contentMaxLength}',
alignLabelWithHint: true,
),
maxLength: PostValidation.contentMaxLength,
maxLines: 10,
validator: (value) => PostValidation.validateContent(value),
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 24),
FilledButton(
onPressed: _isSubmitting ? null : _submit,
child: _isSubmitting
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Text('Publish Post'),
),
],
),
),
);
}
}
GlobalKey دے دو _submit() آپ بیک وقت تمام فیلڈز پر توثیق کو متحرک کرنے کے لیے فارم کی حالت تک رسائی حاصل کر سکتے ہیں۔ _formKey.currentState?.validate() کال validator تمام خصوصیات TextFormField فارمیٹ میں واپسی true یہ صرف اس صورت میں ممکن ہے جب تمام تصدیق کنندگان null واپس کریں۔ توثیق کی ناکامی پر قبل از وقت واپسی فارم کے غلط ہونے پر نیٹ ورک کالز کو روکتا ہے۔ _isSubmitting ڈرائیو UI حالت۔ بٹن غیر فعال ہے (onPressed: null) جب کال جاری ہے۔ CircularProgressIndicator صارفین کو کیا ہو رہا ہے اس کے بارے میں واضح تاثرات دینے کے لیے بٹن لیبلز کو بدل دیتا ہے۔ if (!mounted) return غیر مطابقت پذیر اندرونی _submit() طریقہ کال کو روکتا ہے۔ setState یا Navigator "setState called after dispose” کی خرابی ویجٹ پر ہوتی ہے جو پہلے ہی درخت سے ہٹا دیے گئے ہیں۔ کہ finally بلاکس کی ضمانت ہے۔ _isSubmitting یہاں تک کہ اگر ایک استثناء پھینک دیا جاتا ہے، تو یہ ہمیشہ غلط پر دوبارہ ترتیب دیا جائے گا، بٹن کو لوڈنگ حالت میں مستقل طور پر پھنسنے سے روکتا ہے۔
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'dart:io' show Platform;
import 'firebase_options.dart';
import 'features/create_post/create_post_screen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
if (const bool.fromEnvironment('USE_EMULATOR', defaultValue: false)) {
final host = Platform.isAndroid ? '10.0.2.2' : 'localhost';
FirebaseFunctions.instance.useFunctionsEmulator(host, 5001);
}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Full-Stack Dart Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const CreatePostScreen(),
);
}
}
WidgetsFlutterBinding.ensureInitialized() کسی بھی فلٹر پلگ ان کوڈ کو کال کرنا ضروری ہے جس میں Firebase کی ابتداء عمل میں لائی جائے۔ اس کے بغیر فون Firebase.initializeApp() پہلے runApp() ایک خرابی ہوتی ہے۔ DefaultFirebaseOptions.currentPlatform جو تخلیق کیا گیا اس سے پڑھیں۔ firebase_options.dart اپنے موجودہ پلیٹ فارم کے لیے درست Firebase پروجیکٹ کنفیگریشن حاصل کرنے کے لیے فائل کا استعمال کریں۔ const bool.fromEnvironment('USE_EMULATOR', defaultValue: false) ایک کمپائل ٹائم مستقل پڑھتا ہے جسے گزر کر سیٹ کیا جاسکتا ہے: --dart-define=USE_EMULATOR=true آپ کو flutter run حکم ایمولیٹرز کو تبدیل کرنے کا یہ طریقہ استعمال کرنے سے زیادہ محفوظ ہے: kDebugModeکیونکہ ریلیز کی تعمیر اس طرح دکھتی ہے: kDebugMode اسے غلط پر سیٹ کرنے سے ایمولیٹر غیر فعال ہو جائے گا، لیکن ریلیز بلڈز مرتب کیے جائیں گے ورنہ نہیں ہوں گے۔ --dart-define=USE_EMULATOR=true واضح طور پر ایک ہی نتیجہ حاصل کرتا ہے۔ Platform.isAndroid اپنے پلیٹ فارم کے لیے درست ایمولیٹر ہوسٹ ایڈریس منتخب کریں جیسا کہ سیٹنگز سیکشن میں بیان کیا گیا ہے۔
نتیجہ
ڈارٹ آن کلاؤڈ فنکشنز ایک ایسی خصوصیت ہے جس کی فلٹر کمیونٹی برسوں سے خواہش مند تھی، اور گوگل کلاؤڈ نیکسٹ 2026 کا اعلان اس قسم کے جوش و خروش کے ساتھ کیا گیا جو صرف اس وقت آتا ہے جب دیرینہ مسائل بالآخر حل ہو جائیں۔ 2023 سے جمع شدہ درخواستوں کا صارف کی آواز کا دھاگہ مبارکبادوں سے بھرا ہوا تھا۔ وہ ڈویلپر جنہوں نے بیک اینڈ فنکشنز لکھنے کے لیے کافی ٹائپ اسکرپٹ سیکھ لیا ہے اور وہ اس سے ناواقف ہیں ان کے پاس اچانک اس زبان میں واپس جانے کا راستہ ہے جو وہ جانتے ہیں۔
تکنیکی بنیاد واقعی ٹھوس ہے۔ ڈارٹ کی اے او ٹی تالیف میں تشریح شدہ رن ٹائم سے کم کولڈ اسٹارٹ ٹائم ہوتا ہے۔ ایک غیر محفوظ، مضبوطی سے ٹائپ شدہ نظام مشترکہ پیکیج پیٹرن کو خواہش کے بجائے قابل اعتماد بناتا ہے۔ غیر مطابقت پذیر ماڈل I/O- پابند سرور کے بغیر کام کے بوجھ کو مؤثر طریقے سے ہینڈل کرتا ہے۔ کہ firebase_functions یہ پیکج FlutterFire پیکیج کے ergonomics کی عکاسی کرتا ہے جسے Flutter ڈویلپرز پہلے ہی استعمال کر رہے ہیں، اس لیے ان لوگوں کے لیے سیکھنے کا ایک کم وکر ہے جن کے پاس پہلے سے ہی Firebase اپنے کلائنٹس میں ضم ہے۔
تجرباتی حالت حقیقی ہے اور اس کا احترام کیا جانا چاہیے۔ پس منظر کے محرکات کو ابھی تک تعینات نہیں کیا جا سکتا۔ مجھے فائر بیس کنسول میں ڈارٹ کی فعالیت نظر نہیں آ رہی ہے۔ نام کی بنیاد پر قابل کال کالنگ کام نہیں کرتی ہے۔ یہ کاغذ کے ایک ٹکڑے تک محدود نہیں ہے۔ یہ حقیقی دنیا کے آرکیٹیکچرل فیصلوں کو متاثر کرے گا، اور ٹیموں کو اس کے ارد گرد واضح طور پر ڈیزائن کرنا چاہیے بجائے اس کے کہ اسے ریلیز کی تاریخ سے پہلے حل کر لیا جائے گا۔ Firebase ٹیم اس خصوصیت کو فعال طور پر تیار کر رہی ہے، اور اعلان کے بعد سے پیش رفت کی رفتار حوصلہ افزا رہی ہے، لیکن پیداواری نظام کو قدامت پسندی سے منصوبہ بندی کرنی چاہیے۔
مشترکہ پیکجز آپ کے فن تعمیر کا مرکزی خیال بنانے کے قابل ہیں، قطع نظر اس کے کہ ڈارٹ کی فنکشنل صلاحیتیں کتنی ہی پختہ ہوجاتی ہیں۔ یہاں تک کہ اگر ہم ٹرگر کی حدود کی وجہ سے Node.js میں ابھی کچھ بیک اینڈ لاجک رکھتے ہیں، دونوں طرف سے کھینچے گئے مشترکہ ڈارٹ پیکج میں مشترکہ ڈیٹا ماڈل اور توثیق کی منطق کی تعمیر فوری طور پر آپ کے کوڈ بیس کو بہتر بنائے گی۔ ہر بار جب آپ فالتو قسم کی تعریف یا دستی طور پر برقرار رکھا API معاہدہ ہٹاتے ہیں، تو آپ کیڑے کے زمرے کو ختم کرتے ہیں جسے جانچ کی کوئی مقدار مکمل طور پر ختم نہیں کر سکتی۔ پیکیجز اب دستیاب ہیں اور ڈارٹ فیچر میں ایمپلیفائرز شامل ہیں جو ایک مکمل انٹیگریٹڈ اسٹیک کو فعال کرتے ہیں۔
فلٹر کمیونٹی ابھی یہ دیکھنا شروع کر رہی ہے کہ فل اسٹیک ڈارٹ پیمانے پر کیسا لگتا ہے۔ حقیقی دنیا کے منصوبوں میں مشترکہ پیکجوں کو منظم کرنے، ٹیسٹ ایبلٹی کے لیے فنکشنز کی ساخت، کال ایبل اور ایچ ٹی ٹی پی فنکشنز کے درمیان ٹریڈ آف کا انتظام کرنے اور موجودہ حدود کو مناسب طریقے سے سنبھالنے کے نمونے اب بھی قائم کیے جا رہے ہیں۔ یہ ہینڈ بک بنیادی باتیں فراہم کرتی ہے۔ چونکہ مزید ٹیمیں پیداواری کام کا بوجھ جاری کرتی ہیں اور جو کچھ وہ سیکھتی ہیں اس کا اشتراک کرتی ہیں، کمیونٹی باقی کو بھر دے گی۔
حوالہ جات
باضابطہ فائر بیس دستاویزات
اعلانات اور بلاگ پوسٹس
پیکج
-
pub.dev میں firebase_functions
کلاؤڈ فنکشنز کے لیے آفیشل ڈارٹ پیکجز فراہم کرتے ہیں:fireUp،onRequest،onCall،HttpsOptions،CallableOptionsاورFirebaseFunctionsException. https://pub.dev/packages/firebase_functions -
GitHub پر firebase_functions
ماخذ کوڈ، مسائل اور مثالیں۔firebase_functionsڈارٹ پیکیج۔ README اضافی مثالوں اور حدود کی تازہ ترین فہرست پر مشتمل ہے۔
https://github.com/firebase/firebase-functions-dart -
pub.dev میں dart_firebase_admin
ڈارٹ ایڈمن SDK کلاؤڈ فنکشنز (کلاؤڈ رن، اسٹینڈ اسٹون سرورز، کمانڈ لائن اسکرپٹس) کے باہر استعمال کے لیے۔ Invertase کی طرف سے منظم. https://pub.dev/packages/dart_firebase_admin -
گٹ ہب پر ڈارٹ_فائربیس_ایڈمن
ڈارٹ ایڈمن SDK کے لیے ماخذ کوڈ اور دستاویزات، بشمول Firestore، تصدیق، کلاؤڈ اسٹوریج، اور FCM کی مثالیں۔ https://github.com/invertase/dart_firebase_admin -
google_cloud_firestore pub.dev میں
فائر اسٹور آپریشنز کے لیے ڈارٹ کلاؤڈ فنکشنز کے اندر استعمال ہونے والا اسٹینڈ اسٹون ڈارٹ فائر اسٹور SDK۔
https://pub.dev/packages/google_cloud_firestore
Codelabs اور سبق
متعلقہ فلٹر اور ڈارٹ پیکجز
یہ ہینڈ بک مئی 2026 میں گوگل کلاؤڈ نیکسٹ 2026 میں اعلان کردہ تجرباتی ڈارٹ کلاؤڈ فنکشن سپورٹ کی عکاسی کرنے کے لیے لکھی گئی تھی۔ firebase_functions ورژن 0.1.x اور کے لیے پیکجز dart_firebase_admin یہ Invertase کے زیر انتظام ایک پیکیج ہے۔ یہ خصوصیت تجرباتی ہے، لہذا API اور معاون ٹرگر کی قسمیں مستقبل کی ریلیز میں تبدیل ہو سکتی ہیں۔ اپ گریڈ کرنے سے پہلے ہمیشہ باضابطہ Firebase دستاویزات اور پیکیج کی تبدیلی کے لاگ کو دیکھیں۔