השתמש מחדש בקוד ה-Cloud Functions שלך בתור תוסף Firebase

1. לפני שמתחילים

תוסף Firebase מבצע משימה או קבוצת משימות ספציפיים בתגובה לבקשות HTTP או הפעלת אירועים ממוצרי Firebase ו-Google אחרים כמו Firebase Cloud Messaging, Cloud Firestore או Pub/Sub.

מה שתבנה

במעבדת הקוד הזה, תבנה תוסף Firebase עבור geoashing . לאחר הפריסה, התוסף שלך ממיר קואורדינטות X ו-Y ל-geohashes בתגובה לאירועי Firestore או באמצעות הפעלת פונקציות הניתנות להתקשרות. זה יכול לשמש כחלופה להטמעת ספריית geofire בכל פלטפורמות היעד שלך לאחסון נתונים, וחוסך לך זמן.

תוסף ה-geohash מוצג במסוף Firebase

מה תלמד

  • כיצד לקחת קוד קיים של Cloud Functions ולהפוך אותו לתוסף Firebase שניתן להפצה
  • כיצד להגדיר קובץ extension.yaml
  • כיצד לאחסן מחרוזות רגישות (מפתחות API) בהרחבה
  • כיצד לאפשר למפתחי התוסף להגדיר אותו כך שיתאים לצרכיהם
  • כיצד לבדוק ולפרוס את ההרחבה

מה אתה צריך

  • Firebase CLI (התקנה וכניסה)
  • חשבון גוגל, כמו חשבון Gmail
  • Node.js ו- npm
  • סביבת הפיתוח המועדפת עליך

2. תתכוננו

קבל את הקוד

כל מה שאתה צריך עבור הרחבה זו נמצא בריפו של GitHub. כדי להתחיל, קח את הקוד ופתח אותו בסביבת הפיתוח המועדפת עליך.

  1. פרק את קובץ ה-zip שהורדת.
  2. כדי להתקין את התלות הנדרשת, פתח את הטרמינל בספריית functions והפעל את הפקודה npm install .

הגדר את Firebase

מעבד קוד זה מעודד מאוד את השימוש באמולטורים של Firebase. אם אתה רוצה לנסות פיתוח תוספים עם פרויקט Firebase אמיתי, ראה יצירת פרויקט Firebase . מעבד קוד זה משתמש בפונקציות ענן, כך שאם אתה משתמש בפרויקט Firebase אמיתי במקום באמולטורים, עליך לשדרג לתוכנית התמחור של Blaze .

רוצה לדלג קדימה?

אתה יכול להוריד גרסה מלאה של Codelab. אם אתה נתקע בדרך או אם אתה רוצה לראות איך נראה הרחבה שהושלמה, בדוק את ענף codelab-end של מאגר GitHub או הורד את ה-zip שהושלם.

3. עיין בקוד

  • פתח את הקובץ index.ts מקובץ ה-zip. שימו לב שהוא מכיל בתוכו שתי הצהרות של פונקציות ענן.

מה עושות הפונקציות הללו?

פונקציות הדגמה אלו משמשות לגיאואשינג. הם לוקחים זוג קואורדינטות והופכים אותם לפורמט המותאם לשאילתות גיאוגרפיות ב-Firestore. הפונקציות מדמות את השימוש בקריאת API כך שתוכל ללמוד עוד על טיפול בסוגי נתונים רגישים בתוספים. למידע נוסף, עיין בתיעוד על הפעלת שאילתות גיאוגרפיות על נתונים ב-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/ אוסף ולאחר מכן מעבדת geoash עבור המסמכים האלה. לאחר מכן הוא מוציא את ה-hash לשדה hash באותו מסמך.

פונקציות הניתנות להתקשרות

הפונקציה הבאה בקובץ 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 ומחזירה geoash. למרות שפונקציה זו לא תיקרא ישירות במעבדת הקוד הזה, היא כלולה כאן כדוגמה למשהו להגדרה בהרחבה של Firebase.

4. הגדר קובץ extension.yaml

עכשיו כשאתה יודע מה עושה קוד Cloud Functions בתוסף שלך, אתה מוכן לארוז אותו להפצה. כל הרחבת Firebase מגיעה עם קובץ extension.yaml שמתאר מה התוסף עושה וכיצד הוא מתנהג.

קובץ extension.yaml דורש כמה מטא נתונים ראשוניים לגבי ההרחבה שלך. כל אחד מהשלבים הבאים עוזר לך להבין מה המשמעות של כל השדות ומדוע אתה צריך אותם.

  1. צור קובץ extension.yaml בספריית הבסיס של הפרויקט שהורדת קודם לכן. התחל על ידי הוספת הדברים הבאים:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

שם התוסף משמש כבסיס של מזהה המופע של התוסף (משתמשים יכולים להתקין מספר מופעים של הרחבה, כל אחד עם מזהה משלו). לאחר מכן, Firebase יוצר את השם של חשבונות השירות של התוסף והמשאבים הספציפיים לתוסף באמצעות מזהה מופע זה. מספר הגרסה מציין את הגרסה של התוסף שלך. זה חייב לעקוב אחר ניהול גרסאות סמנטי , ואתה צריך לעדכן אותו בכל פעם שאתה מבצע שינויים בפונקציונליות של התוסף. גרסת מפרט ההרחבה משמשת כדי לקבוע איזה מפרט תוספי Firebase לעקוב, במקרה זה, נעשה שימוש v1beta .

  1. הוסף כמה פרטים ידידותיים למשתמש לקובץ YAML:
...

displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.

שם התצוגה הוא ייצוג ידידותי של שם התוסף שלך כאשר מפתחים מקיימים אינטראקציה עם התוסף שלך. התיאור נותן סקירה קצרה של מה התוסף עושה. כאשר התוסף נפרס ב- extensions.dev , זה נראה בערך כך:

תוסף Geohash Converter כפי שניתן לראות ב-extensions.dev

  1. ציין את הרישיון עבור הקוד בהרחבה שלך.
...

license: Apache-2.0  # The license you want for the extension
  1. ציין מי כתב את התוסף והאם נדרש חיוב כדי להתקין אותו:
...

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 מכיוון שהסיומת לא תיצור משאבים אוטומטית מקוד בתיקיית הפונקציות. אם פונקציות הענן שלך לא הוכרזו במפורש כמשאב, לא ניתן לפרוס אותן בעת ​​פריסת ההרחבה.

מיקום הפריסה המוגדר על ידי המשתמש

  1. אפשר למשתמש לציין את המיקום שבו הוא רוצה לפרוס תוסף זה ולהחליט אם עדיף לארח את התוסף קרוב יותר למשתמשי הקצה שלו או קרוב יותר למסד הנתונים שלו. בקובץ extension.yaml , כלול את האפשרות לבחור מיקום.

extension.yaml

כעת אתה מוכן לכתוב את התצורה עבור משאב הפונקציה.

  1. בקובץ 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 , שנמצא ב- Write Cloud Functions עבור תיעוד התוסף שלך . אתה מגדיר את resource כמיקום המסמכים. מכיוון שהמטרה הנוכחית שלך היא לשקף את מה שקיים בקוד, נתיב המסמך מקשיב users/{uid} , כאשר מיקום ברירת המחדל של מסד הנתונים לפניו.

  1. התוסף זקוק להרשאות קריאה וכתיבה עבור מסד הנתונים של Firestore. בסוף הקובץ extension.yaml , ציין את תפקידי IAM שאליהם אמורה להיות גישה לתוסף כדי לעבוד עם מסד הנתונים בפרויקט Firebase של המפתח.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

התפקיד datastore.user מגיע מרשימת תפקידי IAM הנתמכים עבור הרחבות . מכיוון שהתוסף הולך להיות קריאה וכתיבה, תפקיד datastore.user מתאים כאן.

  1. יש להוסיף גם את הפונקציה הניתנת להתקשרות. בקובץ 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!

  1. אם עדיין לא עשית זאת, התקשר ל- npm run build בתיקיית הפונקציות של פרויקט ההרחבות שהורדת.
  2. צור ספרייה חדשה במערכת המארחת שלך וחבר את הספרייה לפרויקט 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.
  1. מאותה ספרייה, הפעל את 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.

צילום מסך של תהליך התקנת ההרחבה המראה שהקובץ המקומי משמש לסודות בעת התקנת הרחבה זו

  1. הפעל את האמולטורים של Firebase עם התצורה החדשה:
firebase emulators:start
  1. לאחר הפעלת emulators:start , נווט ללשונית Firestore בתצוגת האינטרנט של האמולטורים.
  2. הוסף מסמך לאוסף users עם שדה מספר xv ושדה מספר yv .

תיבת דו-שיח שמוצגת באמולטורים של Firebase כדי להתחיל אוסף עם מזהה האוסף המכיל את הביטוי

  1. אם הצלחת להתקין את התוסף, התוסף יוצר שדה חדש בשם hash במסמך.

אוסף המשתמשים עם מסמך משתמש הכולל שדה xv, yv ו-hash.

נקה כדי למנוע קונפליקטים

  • לאחר שתסיים לבדוק, הסר את התקנת התוסף - אתה עומד לעדכן את קוד התוסף ולא רוצה להתנגש עם התוסף הנוכחי מאוחר יותר.

הרחבות מאפשרות התקנת גרסאות מרובות של אותה הרחבה בבת אחת, כך שעל ידי הסרת ההתקנה, אתה מבטיח שאין התנגשויות עם הרחבה שהותקנה בעבר.

firebase ext:uninstall geohash-ext

הפתרון הנוכחי עובד, אך כפי שהוזכר בתחילת הפרויקט, יש מפתח API מקודד קשה כדי לדמות תקשורת עם שירות. כיצד תוכל להשתמש במפתח ה-API של משתמש הקצה במקום זה שסופק במקור? המשך לקרוא כדי לגלות.

6. הפוך את ההרחבה לניתנת להגדרה

בשלב זה ב-codelab, יש לך הרחבה שמוגדרת לשימוש עם ההגדרה הדעתנית של הפונקציות שכבר כתבת, אבל מה אם המשתמש שלך רוצה להשתמש בקו רוחב וקו אורך במקום y ו- x עבור השדות המציינים את מיקום במטוס קרטזי? כמו כן, כיצד תוכל לגרום למשתמש הקצה לספק מפתח API משלו, במקום לתת לו לצרוך את מפתח ה-API שסופק? אתה יכול לחרוג במהירות את המכסה עבור ה-API הזה. במקרה זה, אתה מגדיר פרמטרים ומשתמש בהם.

הגדר פרמטרים בסיסיים בקובץ extension.yaml

התחל על ידי המרת הפריטים שעשויים למפתחים להיות להם תצורה מותאמת אישית. הראשון יהיה הפרמטרים XFIELD ו- YFIELD .

  1. בקובץ 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 נותן שמות לפרמטר בצורה גלויה לך, מפיק ההרחבה. השתמש בערך זה מאוחר יותר בעת ציון ערכי הפרמטרים.
  • תווית היא מזהה קריא אנושי למפתח כדי לאפשר להם לדעת מה הפרמטר עושה.
  • תיאור נותן תיאור מפורט של הערך. מכיוון שזה תומך בסימון, זה יכול לקשר לתיעוד נוסף, או שהוא יכול להדגיש מילים שעשויות להיות חשובות למפתח.
  • type מגדיר את מנגנון הקלט לאופן שבו משתמש יגדיר את ערך הפרמטר. ישנם סוגים רבים שקיימים, כולל string , select , multiSelect , selectResource ו- secret . למידע נוסף על כל אחת מהאפשרויות הללו, עיין בתיעוד .
  • validationRegex מגביל את כניסת המפתח לערך רגולרי מסוים (בדוגמה הוא מבוסס על הנחיות שמות השדה הפשוטות שנמצאו כאן ); ואם זה לא יצליח...
  • validationErrorMessage מתריע בפני המפתח על ערך הכשל.
  • ברירת המחדל היא מה יהיה הערך אם המפתח לא יזין שום טקסט.
  • נדרש פירושו שהמפתח אינו נדרש להזין טקסט כלשהו.
  • immutable מאפשר למפתח לעדכן תוסף זה ולשנות ערך זה. במקרה זה, המפתח אמור להיות מסוגל לשנות שמות שדות ככל שהדרישות שלו משתנות.
  • הדוגמה מספקת מושג כיצד עשוי להיראות קלט חוקי.

זה היה הרבה להבין!

  1. יש לך עוד שלושה פרמטרים להוסיף לקובץ 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

הגדר פרמטרים רגישים

כעת, עליך לנהל את מפתח ה-API שהמשתמש מציין. זוהי מחרוזת רגישה שאסור לאחסן בטקסט רגיל בפונקציה. במקום זאת, אחסן את הערך הזה ב- Cloud Secret Manager . זהו מיקום מיוחד בענן המאחסן סודות מוצפנים, ומונע מהם דליפות בטעות. זה מחייב את המפתח לשלם עבור השימוש בשירות זה, אבל זה מוסיף שכבת אבטחה נוספת על מפתחות ה-API שלו ועלול להגביל פעילות הונאה. תיעוד המשתמש מתריע בפני המפתח כי מדובר בשירות בתשלום, כך שלא יהיו הפתעות בחיוב. בסך הכל, השימוש דומה למשאבי המחרוזת האחרים שהוזכרו לעיל. ההבדל היחיד הוא הסוג שנקרא 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!;

בדרך כלל, אתה רוצה לבצע בדיקות null עם ערכי משתני הסביבה, אבל במקרה זה, אתה סומך על כך שערכי הפרמטרים מועתקים כהלכה. הקוד מוגדר כעת לעבוד עם פרמטרי ההרחבה.

7. צור תיעוד משתמש

לפני בדיקת הקוד באמולטורים או בשוק ההרחבות של Firebase, יש לתעד את התוסף כדי שהמפתחים ידעו מה הם מקבלים כשהם משתמשים בתוסף.

  1. התחל על ידי יצירת הקובץ 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)
  1. כדי לחסוך זמן בכתיבת ה- README.md עבור פרויקט זה, השתמש בשיטת הנוחות:
firebase ext:info . --markdown > README.md

זה משלב את התוכן של קובץ PREINSTALL.md שלך ופרטים נוספים על ההרחבה שלך מקובץ extension.yaml שלך.

לבסוף, הודע למפתח התוסף על כמה פרטים נוספים לגבי התוסף שזה עתה הותקן. המפתח עשוי לקבל כמה הוראות ומידע נוספים לאחר השלמת ההתקנה וייתכן שיקבל כמה משימות מפורטות לאחר ההתקנה כמו הגדרת קוד לקוח כאן.

  1. צור קובץ 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

  1. צור ספרייה חדשה במערכת המארחת שלך וחבר את הספרייה לפרויקט Firebase שלך ​​באמצעות firebase init .
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. מאותה ספרייה, הפעל את firebase ext:install כדי להתקין את התוסף. החלף את /path/to/extension בנתיב המוחלט לספרייה המכילה את קובץ extension.yaml שלך. זה מתחיל את תהליך ההתקנה של התוסף שלך ויוצר קובץ .env המכיל את התצורות שלך לפני דחיפה של התצורה ל-Firebase או לאמולטורים.
firebase ext:install /path/to/extension
  • מכיוון שאתה פורס את הפרויקט באופן מקומי, ציין שברצונך להשתמש בקובץ מקומי במקום ב-Google Cloud Secret Manager.

da928c65ffa8ce15.png

  1. התחל את חבילת האמולטור המקומית:
firebase emulators:start

התקן ובדוק עם פרויקט Firebase אמיתי

אתה יכול להתקין את התוסף שלך בפרויקט Firebase בפועל. מומלץ להשתמש בפרויקט בדיקה לצורך הבדיקה שלך. השתמש בזרימת עבודה זו של בדיקה אם ברצונך לבדוק את הזרימה מקצה לקצה של התוסף שלך או אם הטריגר של התוסף שלך עדיין לא נתמך על ידי חבילת האמולטורים של Firebase (ראה את אפשרות אמולטור התוספים ). האמולטורים תומכים כיום בפונקציות המופעלות בקשות HTTP ובפונקציות המופעלות על רקע אירועים עבור Cloud Firestore, Realtime Database ו-Pub/Sub.

  1. צור ספרייה חדשה במערכת המארחת שלך וחבר את הספרייה לפרויקט Firebase שלך ​​באמצעות firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. לאחר מכן, מאותה ספרייה, הפעל את firebase ext:install כדי להתקין את התוסף. החלף את /path/to/extension בנתיב המוחלט לספרייה המכילה את קובץ extension.yaml שלך. זה מתחיל את תהליך ההתקנה של התוסף שלך ויוצר קובץ .env המכיל את התצורות שלך לפני דחיפה של התצורה ל-Firebase או לאמולטורים.
firebase ext:install /path/to/extension
  • מכיוון שאתה רוצה לפרוס ישירות ל-Firebase וברצונך להשתמש ב-Google Cloud Secret Manager, עליך להפעיל את ה-Secret Manager API לפני התקנת התוסף.
  1. פרוס לפרויקט Firebase שלך.
firebase deploy

בדוק את ההרחבה

  1. לאחר הפעלת firebase deploy או firebase emulators:start , נווט ללשונית Firestore של מסוף Firebase או לתצוגת האינטרנט של האמולטורים, לפי הצורך.
  2. הוסף מסמך לאוסף שצוין בשדה x ושדה y . במקרה זה, מסמכים מעודכנים ממוקמים ב- u/{uid} עם שדה x של xv ושדה y של yv .

מסך אמולטורים של Firebase להוספת שיא Firestore

  1. אם הצלחת להתקין את התוסף, התוסף יוצר שדה חדש בשם hash במסמך לאחר שמירת שני השדות.

מסך מסד הנתונים של Firestore מאמולטור המציג חשיש נוסף

8. מזל טוב!

המרת בהצלחה את פונקציית הענן הראשונה שלך לתוסף Firebase!

הוספת קובץ extension.yaml והגדרת אותו כך שמפתחים יוכלו לבחור כיצד הם רוצים לפרוס את התוסף שלך. לאחר מכן יצרת תיעוד משתמש המספק הנחיות לגבי מה על מפתחי התוסף לעשות לפני הגדרת התוסף ומה הצעדים שהם עשויים לנקוט לאחר שהתקינו את התוסף בהצלחה.

כעת אתה יודע את השלבים העיקריים הנדרשים כדי להמיר פונקציית Firebase לתוסף Firebase שניתן להפצה.

מה הלאה?