1. قبل البدء
تنفّذ إحدى إضافات Firebase مهمة أو مجموعة مهام محدّدة استجابةً لطلبات HTTP أو أحداث التشغيل من منتجات Firebase وGoogle الأخرى، مثل "المراسلة عبر السحابة الإلكترونية من Firebase" أو Cloud Firestore أو Pub/Sub.
ما ستنشئه
في هذا الدرس التطبيقي حول الترميز، ستنشئ إضافة Firebase لـ الترميز الجغرافي. بعد نشر الإضافة، تحوّل الإضافة إحداثيات X وY إلى رموز جغرافية مجزّأة استجابةً لأحداث Firestore أو من خلال استدعاءات الدوال القابلة للاستدعاء. يمكن استخدام هذه الطريقة كبديل لتنفيذ مكتبة GeoFire على جميع المنصات المستهدَفة لتخزين البيانات، ما يوفّر لك الوقت.
ما ستتعلمه
- كيفية أخذ رمز Cloud Functions الحالي وتحويله إلى إضافة Firebase قابلة للتوزيع
- كيفية إعداد ملف
extension.yaml
- كيفية تخزين السلاسل الحسّاسة (مفاتيح واجهة برمجة التطبيقات) في إضافة
- كيفية السماح لمطوّري الإضافة بضبطها لتناسب احتياجاتهم
- كيفية اختبار الإضافة ونشرها
المتطلبات
- Firebase CLI (التثبيت وتسجيل الدخول)
- حساب Google، مثل حساب Gmail
- Node.js و
npm
- بيئة التطوير المفضّلة لديك
2. بدء الإعداد
الحصول على الرمز
كل ما تحتاج إليه لهذه الإضافة متوفّر في مستودع GitHub. للبدء، احصل على الرمز وافتحه في بيئة التطوير المفضّلة لديك.
- فكّ ضغط ملف ZIP الذي تم تنزيله.
- لتثبيت العناصر التابعة المطلوبة، افتح الوحدة الطرفية في الدليل
functions
وشغِّل الأمرnpm install
.
إعداد Firebase
يشجّع هذا الدرس التطبيقي بشدة على استخدام محاكيات Firebase. إذا أردت تجربة تطوير الإضافات باستخدام مشروع حقيقي على Firebase، اطّلِع على إنشاء مشروع على Firebase. يستخدم هذا الدرس العملي Cloud Functions، لذا إذا كنت تستخدم مشروعًا حقيقيًا على Firebase بدلاً من المحاكيات، عليك الترقية إلى خطة أسعار Blaze.
هل تريد الانتقال إلى الأمام؟
يمكنك تنزيل نسخة مكتملة من الدرس العملي. إذا واجهتك أي مشاكل أثناء التنفيذ أو أردت الاطّلاع على شكل الإضافة بعد إكمالها، يمكنك مراجعة الفرع codelab-end
من مستودع GitHub أو تنزيل ملف zip المكتمل.
3- مراجعة الرمز البرمجي
- افتح ملف
index.ts
من ملف zip. لاحظ أنّها تحتوي على تعريفَين لوظائف Cloud Functions.
ما هي وظيفة هذه الدوال؟
تُستخدَم وظائف العرض التوضيحي هذه في التجزئة الجغرافية. تأخذ هذه الدوال زوجًا من الإحداثيات وتحوّله إلى تنسيق محسّن لطلبات البحث الجغرافية في Firestore. تحاكي الدوال استخدام طلب من واجهة برمجة التطبيقات حتى تتمكّن من معرفة المزيد عن كيفية التعامل مع أنواع البيانات الحساسة في الإضافات. لمزيد من المعلومات، اطّلِع على المستندات حول تنفيذ طلبات بحث جغرافية على البيانات في Firestore.
ثوابت الدالة
يتم تعريف الثوابت في وقت مبكر، في أعلى ملف index.ts
. يتم الرجوع إلى بعض هذه الثوابت في المشغّلات المحدّدة للإضافة.
index.ts
import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";
initializeApp();
const service = new GeoHashService(apiKey);
مشغّل Firestore
تبدو الدالة الأولى في ملف index.ts
على النحو التالي:
index.ts
export const locationUpdate = firestore.document(documentPath)
.onWrite((change) => {
// item deleted
if (change.after == null) {
return 0;
}
// double check that both values exist for computation
if (
!fieldValueExists(change.after.data(), xField) ||
!fieldValueExists(change.after.data(), yField)
) {
return 0;
}
const x: number = change.after.data()![xField];
const y: number = change.after.data()![yField];
const hash = service.convertToHash(x, y);
// This is to check whether the hash value has changed. If
// it hasn't, you don't want to write to the document again as it
// would create a recursive write loop.
if (fieldValueExists(change.after.data(), outputField)
&& change.after.data()![outputField] == hash) {
return 0;
}
return change.after.ref
.update(
{
[outputField]: hash.hash,
}
);
});
هذه الدالة هي عامل تشغيل Firestore. عند وقوع حدث كتابة في قاعدة البيانات، تتفاعل الدالة مع هذا الحدث من خلال البحث عن الحقل xv
والحقل yv
، وإذا كان كلا الحقلين موجودًا، يتم احتساب رمز GeoHash وكتابة الناتج في موقع محدّد لإخراج المستند. يتم تحديد مستند الإدخال من خلال الثابت users/{uid}
، ما يعني أنّ الدالة تقرأ كل مستند مكتوب في المجموعة users/
ثم تعالج رمز geohash لهذه المستندات. ثم يتم إخراج التجزئة إلى حقل التجزئة في المستند نفسه.
الدوال القابلة للاستدعاء
تبدو الدالة التالية في ملف index.ts
على النحو التالي:
index.ts
export const callableHash = onCall((data, context) => {
if (context.auth == undefined) {
return {error: "Only authorized users are allowed to call this endpoint"};
}
const x = data[xField];
const y = data[yField];
if (x == undefined || y == undefined) {
return {error: "Either x or y parameter was not declared"};
}
const result = service.convertToHash(x, y);
if (result.status != ResultStatusCode.ok) {
return {error: `Something went wrong ${result.message}`};
}
return {result: result.hash};
});
لاحظ الدالة onCall
. يشير ذلك إلى أنّ هذه الدالة هي دالة قابلة للاستدعاء، ويمكن استدعاؤها من داخل رمز تطبيق العميل. تأخذ هذه الدالة القابلة للاستدعاء المَعلمتَين x
وy
وتعرض رمز geohash. على الرغم من أنّه لن يتم استدعاء هذه الدالة مباشرةً في هذا الدرس العملي، إلا أنّها مضمّنة هنا كمثال على ما يجب إعداده في إضافة Firebase.
4. إعداد ملف extension.yaml
بعد أن تعرّفت على وظيفة رمز Cloud Functions في الإضافة، أصبحت جاهزًا لتعبئته بغرض توزيعه. تتضمّن كل إضافة من إضافات Firebase ملف extension.yaml
يصف وظيفة الإضافة وطريقة عملها.
يتطلّب ملف extension.yaml
بعض البيانات الوصفية الأولية عن الإضافة. تساعدك كل خطوة من الخطوات التالية في فهم معنى جميع الحقول وسبب حاجتك إليها.
- أنشئ ملف
extension.yaml
في الدليل الجذر للمشروع الذي نزّلته سابقًا. ابدأ بإضافة ما يلي:
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
يُستخدَم اسم الإضافة كأساس لرقم تعريف مثيل الإضافة (يمكن للمستخدمين تثبيت عدة مثيلات من إضافة، ولكل منها رقم تعريف خاص). تنشئ Firebase بعد ذلك اسم حسابات الخدمة الخاصة بالإضافة والموارد الخاصة بالإضافة باستخدام معرّف المثيل هذا. يشير رقم الإصدار إلى إصدار الإضافة. يجب أن يتّبع الإصدار الدلالي، ويجب تعديله كلما أجريت تغييرات على وظائف الإضافة. يتم استخدام إصدار مواصفات الإضافة لتحديد مواصفات إضافات Firebase التي يجب اتّباعها، وفي هذه الحالة، يتم استخدام v1beta
.
- أضِف بعض التفاصيل سهلة الاستخدام إلى ملف YAML:
...
displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.
الاسم المعروض هو تمثيل سهل الاستخدام لاسم الإضافة عندما يتفاعل المطوّرون معها. يقدّم الوصف نظرة عامة موجزة على وظيفة الإضافة. عند نشر الإضافة على extensions.dev، ستظهر على النحو التالي:
- حدِّد ترخيص التعليمات البرمجية في الإضافة.
...
license: Apache-2.0 # The license you want for the extension
- تحديد الجهة التي كتبت الإضافة وما إذا كان يجب الدفع لتثبيتها:
...
author:
authorName: AUTHOR_NAME
url: https://github.com/Firebase
billingRequired: true
يُستخدَم القسم author
لإعلام المستخدمين بمن يمكنهم التواصل معه في حال مواجهة مشاكل في الإضافة أو إذا أرادوا الحصول على مزيد من المعلومات عنها. billingRequired
هي مَعلمة مطلوبة ويجب ضبطها على true
لأنّ جميع الإضافات تعتمد على Cloud Functions، التي تتطلّب خطة Blaze.
يشمل ذلك الحدّ الأدنى لعدد الحقول المطلوبة في ملف extension.yaml
لتحديد هذه الإضافة. لمزيد من التفاصيل حول المعلومات التعريفية الأخرى التي يمكنك تحديدها في إضافة، يُرجى الاطّلاع على المستندات.
5- تحويل رمز Cloud Functions إلى مورد إضافات
مورد الإضافة هو عنصر تنشئه Firebase في المشروع أثناء تثبيت الإضافة. بعد ذلك، يملك الامتداد هذه الموارد ولديه حساب خدمة محدّد يعمل عليها. في هذا المشروع، تكون هذه الموارد هي Cloud Functions، ويجب تحديدها في ملف extension.yaml
لأنّ الإضافة لن تنشئ تلقائيًا موارد من الرمز في مجلد الدوال. إذا لم يتم تعريف دوال Cloud Functions بشكل صريح كمورد، لا يمكن نشرها عند نشر الإضافة.
الموقع الجغرافي للنشر الذي يحدّده المستخدم
- اسمح للمستخدم بتحديد الموقع الجغرافي الذي يريد نشر هذه الإضافة فيه، وقرِّر ما إذا كان من الأفضل استضافة الإضافة بالقرب من المستخدمين النهائيين أو بالقرب من قاعدة البيانات. في ملف
extension.yaml
، أدرِج خيارًا لاختيار موقع جغرافي.
extension.yaml
أنت الآن جاهز لكتابة إعدادات مورد الدالة.
- في ملف
extension.yaml
، أنشئ عنصر مورد للدالةlocationUpdate
. أضِف ما يلي إلى ملفextension.yaml
:
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
يمكنك تحديد name
كاسم الدالة المعرَّف في ملف index.ts
الخاص بالمشروع. عليك تحديد type
للدالة التي يتم نشرها، ويجب أن تكون firebaseextensions.v1beta.function
دائمًا في الوقت الحالي. بعد ذلك، عليك تحديد properties
لهذه الدالة، والسمة الأولى التي تحدّدها هي eventTrigger
المرتبطة بهذه الدالة. لمطابقة ما توفّره الإضافة حاليًا، يمكنك استخدام eventType
من providers/cloud.firestore/eventTypes/document.write
، والذي يمكن العثور عليه في مستندات كتابة دوال Cloud للإضافة. يمكنك تحديد resource
كموقع للمستندات. بما أنّ هدفك الحالي هو عرض ما هو موجود في الرمز، يستمع مسار المستند إلى users/{uid}
، مع تحديد الموقع الجغرافي التلقائي لقاعدة البيانات قبله.
- تحتاج الإضافة إلى أذونات القراءة والكتابة لقاعدة بيانات Firestore. في نهاية ملف
extension.yaml
، حدِّد أدوار "إدارة الهوية وإمكانية الوصول" التي يجب أن تتمكّن الإضافة من الوصول إليها للعمل مع قاعدة البيانات في مشروع Firebase الخاص بالمطوّر.
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
يأتي الدور datastore.user
من قائمة أدوار إدارة الهوية وإمكانية الوصول المتوافقة مع الإضافات. بما أنّ الإضافة ستتمكّن من القراءة والكتابة، فإنّ الدور datastore.user
مناسب هنا.
- يجب أيضًا إضافة الدالة القابلة للاستدعاء. في ملف
extension.yaml
، أنشئ مرجعًا جديدًا ضمن سمة المراجع. هذه الخصائص خاصة بدالة قابلة للاستدعاء:
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
على الرغم من أنّ المرجع السابق كان يستخدم eventTrigger
، فإنّك هنا تستخدم httpsTrigger
، الذي يغطي كلاً من الدوال القابلة للاستدعاء ودوال HTTPS.
التحقّق من الرمز
كانت عملية الإعداد هذه طويلة لتتمكّن من جعل extension.yaml
يطابق كل ما يفعله الرمز في ملف index.ts
. في هذه المرحلة، يجب أن يظهر ملف extension.yaml
المكتمل على النحو التالي:
extension.yaml
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.
license: Apache-2.0 # The license you want for the extension
author:
authorName: Sparky
url: https://github.com/Firebase
billingRequired: true
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
التحقّق من الحالة
في هذه المرحلة، تكون قد أعددت الأجزاء الوظيفية الأولية للإضافة، لذا يمكنك تجربتها باستخدام محاكيات Firebase.
- إذا لم يسبق لك إجراء ذلك، اتّصِل بالرقم
npm run build
في مجلد الدوال الخاص بمشروع الإضافات الذي تم تنزيله. - أنشئ دليلاً جديدًا على نظامك المضيف واربط هذا الدليل بمشروعك على Firebase باستخدام
firebase init
.
cd .. mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
- من الدليل نفسه، شغِّل
firebase ext:install
. استبدِل/path/to/extension
بالمسار المطلق للدليل الذي يحتوي على ملفextension.yaml
.
firebase ext:install /path/to/extension
This command does two things:
- سيُطلب منك تحديد إعدادات نسخة الإضافة، وسيتم إنشاء ملف
*.env
يحتوي على معلومات الإعدادات الخاصة بالنسخة. - يضيف هذا الإجراء مثيل الإضافة إلى القسم
extensions
منfirebase.json
. يعمل هذا الملف كخريطة تربط بين معرّف المثيل وإصدار الإضافة. - بما أنّك ستنفّذ المشروع محليًا، يمكنك تحديد أنّك تريد استخدام ملف محلي بدلاً من Google Cloud Secret Manager.
- ابدأ محاكيات Firebase باستخدام الإعداد الجديد:
firebase emulators:start
- بعد تنفيذ
emulators:start
، انتقِل إلى علامة التبويب Firestore في عرض الويب الخاص بالمحاكيات. - أضِف مستندًا إلى المجموعة
users
مع حقل الرقمxv
وحقل الرقمyv
.
- إذا تمكّنت من تثبيت الإضافة بنجاح، ستنشئ الإضافة حقلًا جديدًا باسم
hash
في المستند.
تنظيف البيانات لتجنُّب التعارضات
- بعد الانتهاء من الاختبار، أزِل الإضافة لأنّك ستعدّل رمز الإضافة ولا تريد حدوث تعارض مع الإضافة الحالية لاحقًا.
تسمح الإضافات بتثبيت إصدارات متعددة من الإضافة نفسها في الوقت نفسه، لذا من خلال إلغاء التثبيت، يمكنك التأكّد من عدم حدوث أي تعارض مع إضافة تم تثبيتها سابقًا.
firebase ext:uninstall geohash-ext
الحل الحالي يعمل، ولكن كما ذكرنا في بداية المشروع، هناك مفتاح لواجهة برمجة التطبيقات مبرمَج مسبقًا لمحاكاة التواصل مع إحدى الخدمات. كيف يمكن استخدام مفتاح واجهة برمجة التطبيقات الخاص بالمستخدم النهائي بدلاً من المفتاح الذي تم توفيره في الأصل؟ تابِع القراءة لمعرفة المزيد.
6. إتاحة إمكانية ضبط الإضافة من قِبل المستخدم
في هذه المرحلة من الدرس العملي، لديك إضافة تم إعدادها لاستخدامها مع الإعدادات المحدّدة مسبقًا للدوال التي كتبتها، ولكن ماذا لو أراد المستخدم استخدام خطوط الطول والعرض بدلاً من y وx للحقول التي تشير إلى الموقع الجغرافي على مستوى ديكارتي؟ بالإضافة إلى ذلك، كيف يمكن للمستخدم النهائي تقديم مفتاح واجهة برمجة التطبيقات الخاص به بدلاً من السماح له باستخدام مفتاح واجهة برمجة التطبيقات المقدَّم؟ وقد تتجاوز الحصة المخصّصة لواجهة برمجة التطبيقات هذه بسرعة. في هذه الحالة، يمكنك إعداد المَعلمات واستخدامها.
تحديد المَعلمات الأساسية في extension.yaml
ملف
ابدأ بتحويل العناصر التي قد يوفّر لها المطوّرون إعدادات مخصّصة. المَعلمتان الأولى والثانية هما XFIELD
وYFIELD
.
- في الملف
extension.yaml
، أضِف الرمز التالي الذي يستخدم مَعلمتَي الحقلXFIELD
وYFIELD
. تتوفّر هذه المَعلمات داخل سمةparams
YAML المحدّدة سابقًا:
extension.yaml
params:
- param: XFIELD
label: The X Field Name
description: >-
The X Field is also known as the **longitude** value. What does
your Firestore instance refer to as the X value or the longitude
value. If no value is specified, the extension searches for
field 'xv'.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: xv
required: false
immutable: false
example: xv
- param: YFIELD
label: The Y Field Name
description: >-
The Y Field is also known as the **latitude** value. What does
your Firestore instance refer to as the Y value or the latitude
value. If no value is specified, the extension searches for
field 'yv'.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: yv
required: false
immutable: false
example: yv
- يسمّي param المَعلمة بطريقة تظهر لك، أي منتج الإضافة. استخدِم هذه القيمة لاحقًا عند تحديد قيم المَعلمات.
- label هو معرّف يمكن للمطوّر قراءته لمعرفة وظيفة المَعلمة.
- تقدّم السمة description وصفًا تفصيليًا للقيمة. بما أنّ هذا الحقل يتيح استخدام لغة الترميز Markdown، يمكنه إنشاء روابط تؤدي إلى مستندات إضافية، أو يمكنه تمييز الكلمات التي قد تكون مهمة للمطوّر.
- تحدّد السمة type آلية الإدخال التي سيستخدمها المستخدم لضبط قيمة المَعلمة. تتوفّر أنواع عديدة، بما في ذلك
string
وselect
وmultiSelect
وselectResource
وsecret
. لمزيد من المعلومات حول كل خيار من هذه الخيارات، يُرجى الاطّلاع على المستندات. - يفرض validationRegex على إدخال المطوّر قيمة تعبير عادي معيّن (في المثال، يستند إلى إرشادات اسم الحقل البسيط الموضّحة هنا)، وفي حال عدم استيفاء هذا الشرط...
- تنبّه السمة validationErrorMessage المطوّر إلى قيمة الخطأ.
- default هي القيمة التي ستظهر إذا لم يُدخل المطوّر أي نص.
- تعني مطلوب أنّه ليس على المطوّر إدخال أي نص.
- تسمح السمة immutable للمطوّر بتعديل هذه الإضافة وتغيير هذه القيمة. في هذه الحالة، يجب أن يتمكّن المطوّر من تغيير أسماء الحقول عند تغيُّر متطلباته.
- تقدّم example فكرة عن الشكل الذي قد يبدو عليه الإدخال الصالح.
كانت هذه معلومات كثيرة يجب فهمها.
- يجب إضافة ثلاث معلَمات أخرى إلى ملف
extension.yaml
قبل إضافة معلَمة خاصة.
- param: INPUTPATH
label: The input document to listen to for changes
description: >-
This is the document where you write an x and y value to. Once
that document has received a value, it notifies the extension to
calculate a geohash and store that in an output document in a certain
field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
type: string
validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
validationErrorMessage: >-
This must point to a document path, not a collection path from the root
of the database. It must also not start or end with a '/' character.
required: true
immutable: false
example: users/{uid}
- param: OUTPUTFIELD
label: Geohash field
description: >-
This specifies the field in the output document to store the geohash in.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
required: false
default: hash
immutable: false
example: hash
تحديد المَعلمات الحسّاسة
عليك الآن إدارة مفتاح واجهة برمجة التطبيقات الذي يحدّده المستخدم. هذه سلسلة حساسة يجب عدم تخزينها كنص عادي في الدالة. بدلاً من ذلك، خزِّن هذه القيمة في Cloud Secret Manager. هذا موقع خاص في السحابة الإلكترونية يخزّن الأسرار المشفّرة ويمنع تسريبها عن طريق الخطأ. يتطلّب ذلك أن يدفع المطوّر مقابل استخدام هذه الخدمة، ولكنّها تضيف طبقة أمان إضافية على مفاتيح واجهة برمجة التطبيقات وقد تحدّ من الأنشطة الاحتيالية. تنبّه مستندات المستخدم المطوّر إلى أنّها خدمة مدفوعة، حتى لا تحدث أي مفاجآت في الفوترة. بشكل عام، يكون الاستخدام مشابهًا لموارد السلاسل الأخرى المذكورة أعلاه. الفرق الوحيد هو النوع الذي يُطلق عليه secret
.
- في ملف
extension.yaml
، أضِف الرمز التالي:
extension.yaml
- param: APIKEY
label: GeohashService API Key
description: >-
Your geohash service API Key. Since this is a demo, and not a real
service, you can use : 1234567890.
type: secret
required: true
immutable: false
تعديل resource
السمات لاستخدام المَعلمات
كما ذكرنا سابقًا، يحدّد المرجع (وليس الدالة) طريقة مراقبة المرجع، لذا يجب تعديل المرجع locationUpdate
من أجل استخدام المَعلمة الجديدة.
- في ملف
extension.yaml
، أضِف الرمز التالي:
extension.yaml
## Change from this
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}]
## To this
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
الاطّلاع على الملف في extension.yaml
- راجِع الملف
extension.yaml
. من المفترض أن تظهر بشكلٍ مشابه لما يلي:
extension.yaml
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.
license: Apache-2.0 # The license you want to use for the extension
author:
authorName: Sparky
url: https://github.com/Firebase
billingRequired: true
params:
- param: XFIELD
label: The X Field Name
description: >-
The X Field is also known as the **longitude** value. What does
your Firestore instance refer to as the X value or the longitude
value. If you don't provide a value for this field, the extension will use 'xv' as the default value.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: xv
required: false
immutable: false
example: xv
- param: YFIELD
label: The Y Field Name
description: >-
The Y Field is also known as the **latitude** value. What does
your Firestore instance refer to as the Y value or the latitude
Value. If you don't provide a value for this field, the extension will use 'yv' as the default value.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: yv
required: false
immutable: false
example: yv
- param: INPUTPATH
label: The input document to listen to for changes
description: >-
This is the document where you write an x and y value to. Once
that document has been modified, it notifies the extension to
compute a geohash and store that in an output document in a certain
field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
type: string
validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
validationErrorMessage: >-
This must point to a document path, not a collection path from the root
of the database. It must also not start or end with a '/' character.
required: true
immutable: false
example: users/{uid}
- param: OUTPUTFIELD
label: Geohash field
description: >-
This specifies the field in the output document to store the geohash in.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
required: false
default: hash
immutable: false
example: hash
- param: APIKEY
label: GeohashService API Key
description: >-
Your geohash service API Key. Since this is a demo, and not a real
service, you can use : 1234567890.
type: secret
required: true
immutable: false
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
الوصول إلى المَعلمات في الرمز
بعد ضبط جميع المَعلمات في الملف extension.yaml
، أضِفها إلى الملف index.ts
.
- في ملف
index.ts
، استبدِل القيم التلقائية بـprocess.env.PARAMETER_NAME
، ما يؤدي إلى جلب قيم المَعلمات المناسبة وتعبئتها في رمز الدالة الذي تم نشره في مشروع Firebase الخاص بالمطوّر.
index.ts
// Replace this:
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";
// with this:
const documentPath = process.env.INPUTPATH!; // this value is ignored since its read from the resource
const xField = process.env.XFIELD!;
const yField = process.env.YFIELD!;
const apiKey = process.env.APIKEY!;
const outputField = process.env.OUTPUTFIELD!;
عادةً، تريد إجراء عمليات التحقّق من القيم الفارغة باستخدام قيم متغيّرات البيئة، ولكن في هذه الحالة، تثق بأنّه تم نسخ قيم المَعلمات بشكل صحيح. تمّ الآن ضبط الرمز للعمل مع مَعلمات الإضافة.
7. إنشاء مستندات المستخدم
قبل اختبار الرمز البرمجي على المحاكيات أو في سوق إضافات Firebase، يجب توثيق الإضافة لكي يعرف المطوّرون ما سيحصلون عليه عند استخدامها.
- ابدأ بإنشاء ملف
PREINSTALL.md
الذي يُستخدَم لوصف الوظائف وأي متطلبات أساسية للتثبيت والآثار المحتملة للفوترة.
PREINSTALL.md
Use this extension to automatically convert documents with a latitude and
longitude to a geohash in your database. Additionally, this extension includes a callable function that allows users to make one-time calls
to convert an x,y coordinate into a geohash.
Geohashing is supported for latitudes between 90 and -90 and longitudes
between 180 and -180.
#### Third Party API Key
This extension uses a fictitious third-party API for calculating the
geohash. You need to supply your own API keys. (Since it's fictitious,
you can use 1234567890 as an API key).
#### Additional setup
Before installing this extension, make sure that you've [set up a Cloud
Firestore database](https://firebase.google.com/docs/firestore/quickstart) in your Firebase project.
After installing this extension, you'll need to:
- Update your client code to point to the callable geohash function if you
want to perform arbitrary geohashes.
Detailed information for these post-installation tasks are provided after
you install this extension.
#### Billing
To install an extension, your project must be on the [Blaze (pay as you
go) plan](https://firebase.google.com/pricing)
- This extension uses other Firebase and Google Cloud Platform services,
which have associated charges if you exceed the service's no-cost tier:
- Cloud Firestore
- Cloud Functions (Node.js 16+ runtime. [See
FAQs](https://firebase.google.com/support/faq#extensions-pricing))
- [Cloud Secret Manager](https://cloud.google.com/secret-manager/pricing)
- لتوفير الوقت في كتابة
README.md
لهذا المشروع، استخدِم طريقة الاختصار التالية:
firebase ext:info . --markdown > README.md
يجمع هذا الملف بين محتوى ملف PREINSTALL.md
والتفاصيل الإضافية عن الإضافة من ملف extension.yaml
.
أخيرًا، أبلِغ مطوّر الإضافة ببعض التفاصيل الإضافية بشأن الإضافة التي تم تثبيتها للتو. قد يتلقّى المطوّر بعض التعليمات والمعلومات الإضافية بعد إكمال عملية التثبيت، وقد يتلقّى بعض المهام التفصيلية بعد التثبيت، مثل إعداد رمز العميل هنا.
- أنشِئ ملف
POSTINSTALL.md
، ثم أدرِج معلومات ما بعد التثبيت التالية:
POSTINSTALL.md
Congratulations on installing the geohash extension!
#### Function information
* **Firestore Trigger** - ${function:locationUpdate.name} was installed
and is invoked when both an x field (${param:XFIELD}) and y field
(${param:YFIELD}) contain a value.
* **Callable Trigger** - ${function:callableHash.name} was installed and
can be invoked by writing the following client code:
```javascript
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const geoHash = httpsCallable(functions, '${function:callableHash.name}');
geoHash({ ${param:XFIELD}: -122.0840, ${param:YFIELD}: 37.4221 })
.then((result) => {
// Read result of the Cloud Function.
/** @type {any} */
const data = result.data;
const error = data.error;
if (error != null) {
console.error(`callable error : ${error}`);
}
const result = data.result;
console.log(result);
});
التتبّع
كأفضل ممارسة، يمكنك مراقبة نشاط الإضافة المثبَّتة، بما في ذلك عمليات التحقّق من سلامتها واستخدامها وسجلّاتها.
The output rendering looks something like this when it's deployed:
<img src="img/82b54a5c6ca34b3c.png" alt="A preview of the latitude and longitude geohash converter extension in the firebase console" width="957.00" />
## Test the extension with the full configuration
Duration: 03:00
It's time to make sure that the user-configurable extension is working the way it is intended.
* Change into the functions folder and ensure that the latest compiled version of the extensions exists. In the extensions project functions directory, call:
```console
npm run build
يؤدي ذلك إلى إعادة تجميع الدوال ليكون أحدث رمز مصدر جاهزًا للنشر مع الإضافة عند نشرها على محاكي أو على Firebase مباشرةً.
بعد ذلك، أنشِئ دليلاً جديدًا لاختبار الإضافة منه. بما أنّ الإضافة تم تطويرها من دوال حالية، لا تجرِّبها من المجلد الذي تم إعداد الإضافة فيه لأنّ ذلك سيحاول أيضًا نشر الدوال وقواعد Firebase معها.
التثبيت والاختبار باستخدام محاكيات Firebase
- أنشئ دليلاً جديدًا على نظامك المضيف واربط هذا الدليل بمشروعك على Firebase باستخدام
firebase init
.
mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- من هذا الدليل، شغِّل
firebase ext:install
لتثبيت الإضافة. استبدِل/path/to/extension
بالمسار المطلق للدليل الذي يحتوي على ملفextension.yaml
. يبدأ هذا الإجراء عملية تثبيت الإضافة وينشئ ملف.env
يحتوي على إعداداتك قبل إرسال الإعدادات إلى Firebase أو إلى المحاكيات.
firebase ext:install /path/to/extension
- بما أنّك ستنفّذ المشروع على جهازك، حدِّد أنّك تريد استخدام ملف محلي بدلاً من Google Cloud Secret Manager.
- ابدأ مجموعة أدوات المحاكاة المحلية:
firebase emulators:start
التثبيت والاختبار باستخدام مشروع حقيقي على Firebase
يمكنك تثبيت الإضافة في مشروع Firebase فعلي. يُنصح باستخدام مشروع تجريبي لإجراء الاختبارات. استخدِم طريقة سير العمل هذه إذا كنت تريد اختبار مسار الإضافة الكامل أو إذا كان مشغّل الإضافة غير متوافق بعد مع حزمة المحاكي في Firebase (راجِع خيار محاكي الإضافات). تتيح المحاكيات حاليًا وظائف يتم تشغيلها عند تلقّي طلب HTTP ووظائف يتم تشغيلها عند تلقّي حدث في الخلفية لكلّ من Cloud Firestore وRealtime Database وPub/Sub.
- أنشئ دليلاً جديدًا على نظامك المضيف واربط هذا الدليل بمشروعك على Firebase باستخدام
firebase init
.
cd .. mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- بعد ذلك، شغِّل
firebase ext:install
من هذا الدليل لتثبيت الإضافة. استبدِل/path/to/extension
بالمسار المطلق للدليل الذي يحتوي على ملفextension.yaml
. يبدأ هذا الإجراء عملية تثبيت الإضافة وينشئ ملف.env
يحتوي على إعداداتك قبل إرسال الإعدادات إلى Firebase أو إلى المحاكيات.
firebase ext:install /path/to/extension
- بما أنّك تريد النشر على Firebase مباشرةً واستخدام Google Cloud Secret Manager، عليك تفعيل واجهة برمجة التطبيقات Secret Manager قبل تثبيت الإضافة.
- نشر الموقع الإلكتروني في مشروعك على Firebase
firebase deploy
تجربة الإضافة
- بعد تنفيذ
firebase deploy
أوfirebase emulators:start
، انتقِل إلى علامة التبويب Firestore في وحدة تحكّم Firebase أو في عرض الويب المضمّن للمحاكيات، حسب الاقتضاء. - أضِف مستندًا إلى المجموعة المحدّدة من خلال الحقل
x
والحقلy
. في هذه الحالة، تقع المستندات المعدَّلة فيu/{uid}
مع حقلx
بقيمةxv
وحقلy
بقيمةyv
.
- إذا نجحت في تثبيت الإضافة، ستنشئ الإضافة حقلًا جديدًا باسم
hash
في المستند بعد حفظ الحقلَين.
8. تهانينا!
لقد نجحت في تحويل أول "دالة سحابية" إلى "إضافة Firebase".
لقد أضفت ملف extension.yaml
وأعددته ليتمكّن المطوّرون من اختيار طريقة نشر الإضافة. بعد ذلك، أنشأت مستندات للمستخدمين تقدّم إرشادات حول ما يجب أن يفعله مطوّرو الإضافة قبل إعدادها والخطوات التي قد يحتاجون إلى اتّخاذها بعد تثبيت الإضافة بنجاح.
أصبحت الآن على دراية بالخطوات الأساسية المطلوبة لتحويل إحدى "وظائف Firebase" إلى "إضافة Firebase" قابلة للتوزيع.