Verwenden Sie Ihren Cloud Functions-Code als Firebase-Erweiterung um

1. Bevor Sie beginnen

Eine Firebase-Erweiterung führt eine bestimmte Aufgabe oder eine Reihe von Aufgaben als Reaktion auf HTTP-Anfragen oder auslösende Ereignisse von anderen Firebase- und Google-Produkten wie Firebase Cloud Messaging, Cloud Firestore oder Pub/Sub aus.

Was Sie bauen werden

In diesem Codelab erstellen Sie eine Firebase-Erweiterung für Geohashing . Nach der Bereitstellung wandelt Ihre Erweiterung als Reaktion auf Firestore-Ereignisse oder durch aufrufbare Funktionsaufrufe X- und Y-Koordinaten in Geohashes um. Dies kann als Alternative zur Implementierung der Geofire-Bibliothek auf allen Ihren Zielplattformen zum Speichern von Daten verwendet werden, wodurch Sie Zeit sparen.

Die Geohash-Erweiterung wird in der Firebase-Konsole angezeigt

Was Sie lernen werden

  • So nehmen Sie vorhandenen Cloud Functions-Code und wandeln ihn in eine verteilbare Firebase-Erweiterung um
  • So richten Sie eine extension.yaml Datei ein
  • So speichern Sie vertrauliche Zeichenfolgen (API-Schlüssel) in einer Erweiterung
  • So ermöglichen Sie Entwicklern der Erweiterung, sie entsprechend ihren Anforderungen zu konfigurieren
  • So testen und stellen Sie die Erweiterung bereit

Was du brauchen wirst

  • Firebase CLI (installieren und anmelden)
  • Ein Google-Konto, wie ein Gmail-Konto
  • Node.js und npm
  • Ihre bevorzugte Entwicklungsumgebung

2. Machen Sie sich bereit

Holen Sie sich den Code

Alles, was Sie für diese Erweiterung benötigen, finden Sie in einem GitHub-Repo. Schnappen Sie sich zunächst den Code und öffnen Sie ihn in Ihrer bevorzugten Entwicklungsumgebung.

  1. Entpacken Sie die heruntergeladene Zip-Datei.
  2. Um die erforderlichen Abhängigkeiten zu installieren, öffnen Sie das Terminal im functions und führen Sie den Befehl npm install aus.

Richten Sie Firebase ein

Dieses Codelab empfiehlt dringend die Verwendung von Firebase-Emulatoren. Wenn Sie die Entwicklung von Erweiterungen mit einem echten Firebase-Projekt ausprobieren möchten, lesen Sie „Erstellen eines Firebase-Projekts“ . Dieses Codelab verwendet Cloud Functions. Wenn Sie also ein echtes Firebase-Projekt anstelle der Emulatoren verwenden, müssen Sie ein Upgrade auf den Blaze-Preisplan durchführen.

Möchten Sie weitermachen?

Sie können eine fertige Version des Codelabs herunterladen. Wenn Sie unterwegs nicht weiterkommen oder sehen möchten, wie eine fertige Erweiterung aussieht, schauen Sie sich den codelab-end Zweig des GitHub-Repositorys an oder laden Sie die fertige ZIP-Datei herunter.

3. Überprüfen Sie den Code

  • Öffnen Sie die Datei index.ts aus der ZIP-Datei. Beachten Sie, dass es zwei Cloud Functions-Deklarationen enthält.

Was bewirken diese Funktionen?

Diese Demofunktionen werden für Geohashing verwendet. Sie nehmen ein Koordinatenpaar und wandeln es in ein Format um, das für Geoabfragen in Firestore optimiert ist. Die Funktionen simulieren die Verwendung eines API-Aufrufs, sodass Sie mehr über den Umgang mit sensiblen Datentypen in Erweiterungen erfahren können. Weitere Informationen finden Sie in der Dokumentation zum Ausführen von Geoabfragen für Daten in Firestore .

Funktionskonstanten

Konstanten werden frühzeitig oben in der Datei index.ts deklariert. Auf einige dieser Konstanten wird in den definierten Triggern der Erweiterung verwiesen.

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-Trigger

Die erste Funktion in der Datei index.ts sieht folgendermaßen aus:

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,
        }
      );
  });

Diese Funktion ist ein Firestore-Trigger . Wenn in der Datenbank ein Schreibereignis auftritt, reagiert die Funktion auf dieses Ereignis, indem sie nach einem xv Feld und einem yv -Feld sucht. Wenn beide Felder vorhanden sind, berechnet sie den Geohash und schreibt die Ausgabe an einen angegebenen Dokumentausgabeort. Das Eingabedokument wird durch die Konstante users/{uid} “ definiert, was bedeutet, dass die Funktion jedes in die Sammlung „ users/ geschriebene Dokument liest und dann einen Geohash für diese Dokumente verarbeitet. Anschließend wird der Hash in ein Hash-Feld im selben Dokument ausgegeben.

Aufrufbare Funktionen

Die nächste Funktion in der Datei index.ts sieht folgendermaßen aus:

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};
});

Beachten Sie die onCall Funktion. Es zeigt an, dass es sich bei dieser Funktion um eine aufrufbare Funktion handelt, die aus Ihrem Clientanwendungscode heraus aufgerufen werden kann. Diese aufrufbare Funktion akzeptiert x und y Parameter und gibt einen Geohash zurück. Obwohl diese Funktion in diesem Codelab nicht direkt aufgerufen wird, ist sie hier als Beispiel für etwas enthalten, das in der Firebase-Erweiterung konfiguriert werden kann.

4. Richten Sie eine extension.yaml-Datei ein

Da Sie nun wissen, was der Cloud Functions-Code in Ihrer Erweiterung bewirkt, können Sie ihn für die Verteilung verpacken. Jede Firebase-Erweiterung wird mit einer Datei extension.yaml geliefert, die beschreibt, was die Erweiterung tut und wie sie sich verhält.

Für eine extension.yaml Datei sind einige anfängliche Metadaten zu Ihrer Erweiterung erforderlich. Jeder der folgenden Schritte hilft Ihnen zu verstehen, was alle Felder bedeuten und warum Sie sie benötigen.

  1. Erstellen Sie eine Datei extension.yaml im Stammverzeichnis des Projekts, das Sie zuvor heruntergeladen haben. Fügen Sie zunächst Folgendes hinzu:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

Der Name der Erweiterung wird als Basis für die Instanz-ID der Erweiterung verwendet (Benutzer können mehrere Instanzen einer Erweiterung installieren, jede mit ihrer eigenen ID). Firebase generiert dann mithilfe dieser Instanz-ID den Namen der Dienstkonten und erweiterungsspezifischen Ressourcen der Erweiterung. Die Versionsnummer gibt die Version Ihrer Erweiterung an. Es muss der semantischen Versionierung folgen und Sie müssen es jedes Mal aktualisieren, wenn Sie Änderungen an der Funktionalität der Erweiterung vornehmen. Die Version der Erweiterungsspezifikation wird verwendet, um zu bestimmen, welche Firebase-Erweiterungsspezifikation befolgt werden soll. In diesem Fall wird v1beta verwendet.

  1. Fügen Sie der YAML-Datei einige benutzerfreundliche Details hinzu:
...

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

Der Anzeigename ist eine benutzerfreundliche Darstellung des Namens Ihrer Erweiterung, wenn Entwickler mit Ihrer Erweiterung interagieren. Die Beschreibung gibt einen kurzen Überblick über die Funktionen der Erweiterung. Wenn die Erweiterung auf extensions.dev bereitgestellt wird, sieht sie in etwa so aus:

Geohash Converter-Erweiterung, wie auf extensions.dev zu sehen

  1. Geben Sie die Lizenz für den Code in Ihrer Erweiterung an.
...

license: Apache-2.0  # The license you want for the extension
  1. Geben Sie an, wer die Erweiterung geschrieben hat und ob für die Installation eine Abrechnung erforderlich ist:
...

author:
  authorName: AUTHOR_NAME
  url: https://github.com/Firebase

billingRequired: true

Der author wird verwendet, um Ihren Benutzern mitzuteilen, an wen sie sich wenden können, falls sie Probleme mit der Erweiterung haben oder weitere Informationen dazu wünschen. billingRequired ist ein erforderlicher Parameter und muss auf true gesetzt werden, da alle Erweiterungen auf Cloud Functions basieren, was den Blaze-Plan erfordert.

Dies deckt die Mindestanzahl an Feldern ab, die in der Datei extension.yaml erforderlich sind, um diese Erweiterung zu identifizieren. Weitere Einzelheiten zu anderen identifizierenden Informationen, die Sie in einer Erweiterung angeben können, finden Sie in der Dokumentation .

5. Konvertieren Sie den Cloud Functions-Code in eine Erweiterungsressource

Eine Erweiterungsressource ist ein Element, das Firebase während der Installation einer Erweiterung im Projekt erstellt. Die Erweiterung ist dann Eigentümer dieser Ressourcen und verfügt über ein bestimmtes Dienstkonto, das mit ihnen arbeitet. In diesem Projekt handelt es sich bei diesen Ressourcen um Cloud-Funktionen, die in der Datei extension.yaml definiert werden müssen, da die Erweiterung nicht automatisch Ressourcen aus Code im Funktionsordner erstellt. Wenn Ihre Cloud-Funktionen nicht explizit als Ressource deklariert sind, können sie bei der Bereitstellung der Erweiterung nicht bereitgestellt werden.

Benutzerdefinierter Bereitstellungsort

  1. Ermöglichen Sie dem Benutzer, den Standort anzugeben, an dem er diese Erweiterung bereitstellen möchte, und zu entscheiden, ob es besser wäre, die Erweiterung näher an seinen Endbenutzern oder näher an ihrer Datenbank zu hosten. Fügen Sie in die Datei extension.yaml die Option zur Auswahl eines Speicherorts ein.

extension.yaml

Sie können nun die Konfiguration für die Funktionsressource schreiben.

  1. Erstellen Sie in der Datei extension.yaml ein Ressourcenobjekt für die locationUpdate Funktion. Hängen Sie Folgendes an die Datei extension.yaml an:
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}

Sie definieren den name als den Funktionsnamen, der in der Datei index.ts des Projekts definiert ist. Sie geben den type der bereitzustellenden Funktion an, der vorerst immer firebaseextensions.v1beta.function lauten sollte. Anschließend definieren Sie die properties dieser Funktion. Die erste Eigenschaft, die Sie definieren, ist der eventTrigger , der dieser Funktion zugeordnet ist. Um zu spiegeln, was die Erweiterung derzeit unterstützt, verwenden Sie den eventType von providers/cloud.firestore/eventTypes/document.write , der in der Dokumentation „Write Cloud Functions“ für Ihre Erweiterung zu finden ist. Sie definieren die resource als Speicherort der Dokumente. Da Ihr aktuelles Ziel darin besteht, das zu spiegeln, was im Code vorhanden ist, hört der Dokumentpfad auf users/{uid} , wobei der Standardspeicherort der Datenbank davor steht.

  1. Die Erweiterung benötigt Lese- und Schreibberechtigungen für die Firestore-Datenbank. Geben Sie ganz am Ende der Datei extension.yaml die IAM-Rollen an, auf die die Erweiterung Zugriff haben soll, um mit der Datenbank im Firebase-Projekt des Entwicklers arbeiten zu können.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Die Rolle datastore.user stammt aus der Liste der unterstützten IAM-Rollen für Erweiterungen . Da die Erweiterung lesen und schreiben soll, passt die Rolle datastore.user hier gut.

  1. Die aufrufbare Funktion muss ebenfalls hinzugefügt werden. Erstellen Sie in der Datei extension.yaml eine neue Ressource unter der Eigenschaft „resources“. Diese Eigenschaften sind spezifisch für eine aufrufbare Funktion:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

Obwohl die vorherige Ressource einen eventTrigger verwendete, verwenden Sie hier einen httpsTrigger , der sowohl aufrufbare Funktionen als auch HTTPS-Funktionen abdeckt.

Codeüberprüfung

Das war eine Menge Konfiguration, damit Ihre extension.yaml mit allem übereinstimmt, was der Code in Ihrer index.ts Datei macht. So sollte die fertige Datei extension.yaml zu diesem Zeitpunkt aussehen:

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.

Statusprüfung

Zu diesem Zeitpunkt haben Sie die ersten Funktionsteile der Erweiterung eingerichtet, sodass Sie sie tatsächlich mit den Firebase-Emulatoren ausprobieren können!

  1. Wenn Sie es noch nicht getan haben, rufen Sie npm run build im Funktionsordner des heruntergeladenen Erweiterungsprojekts auf.
  2. Erstellen Sie ein neues Verzeichnis auf Ihrem Hostsystem und verbinden Sie dieses Verzeichnis mithilfe firebase init mit Ihrem Firebase-Projekt.
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. Führen Sie im selben Verzeichnis firebase ext:install . Ersetzen Sie /path/to/extension durch den absoluten Pfad zu dem Verzeichnis, das Ihre Datei extension.yaml enthält.
firebase ext:install /path/to/extension
    This command does two things:
  • Sie werden aufgefordert, die Konfiguration für die Erweiterungsinstanz anzugeben, und es wird eine *.env Datei erstellt, die die Konfigurationsinformationen für die Instanz enthält.
  • Es fügt die Erweiterungsinstanz zum Abschnitt extensions Ihrer firebase.json hinzu. Dies dient als Zuordnung der Instanz-ID zur Erweiterungsversion.
  • Da Sie das Projekt lokal bereitstellen, können Sie angeben, dass Sie eine lokale Datei anstelle des Google Cloud Secret Managers verwenden möchten.

Screenshot des Installationsprozesses der Erweiterung, der zeigt, dass bei der Installation dieser Erweiterung die lokale Datei für Geheimnisse verwendet wird

  1. Starten Sie die Firebase-Emulatoren mit der neuen Konfiguration:
firebase emulators:start
  1. Navigieren Sie nach dem Ausführen emulators:start zur Registerkarte Firestore in der Webansicht der Emulatoren.
  2. Fügen Sie der users ein Dokument mit einem xv -Nummernfeld und yv -Nummernfeld hinzu.

Ein Dialogfeld, das in den Firebase-Emulatoren angezeigt wird, um eine Sammlung mit der Sammlungs-ID zu starten, die die Phrase enthält

  1. Wenn Sie die Erweiterung erfolgreich installiert haben, erstellt die Erweiterung ein neues Feld namens hash im Dokument.

Die Benutzersammlung mit einem Benutzerdokument mit einem xv-, yv- und Hash-Feld.

Räumen Sie auf, um Konflikte zu vermeiden

  • Sobald Sie mit dem Testen fertig sind, deinstallieren Sie die Erweiterung – Sie aktualisieren den Erweiterungscode und möchten später keinen Konflikt mit der aktuellen Erweiterung haben.

Erweiterungen ermöglichen die gleichzeitige Installation mehrerer Versionen derselben Erweiterung. Durch die Deinstallation stellen Sie also sicher, dass es keine Konflikte mit einer zuvor installierten Erweiterung gibt.

firebase ext:uninstall geohash-ext

Die aktuelle Lösung funktioniert, aber wie zu Beginn des Projekts erwähnt, gibt es einen hartcodierten API-Schlüssel, um die Kommunikation mit einem Dienst zu simulieren. Wie können Sie den API-Schlüssel des Endbenutzers anstelle des ursprünglich bereitgestellten verwenden? Lesen Sie weiter, um es herauszufinden.

6. Machen Sie die Erweiterung vom Benutzer konfigurierbar

An diesem Punkt im Codelab verfügen Sie über eine Erweiterung, die für die Verwendung mit dem eigensinnigen Setup der Funktionen konfiguriert ist, die Sie bereits geschrieben haben. Was aber, wenn Ihr Benutzer Breiten- und Längengrad anstelle von y und x für die Felder verwenden möchte, die angeben? Ort auf einer kartesischen Ebene? Wie können Sie außerdem den Endbenutzer dazu bringen, seinen eigenen API-Schlüssel bereitzustellen, anstatt ihn den bereitgestellten API-Schlüssel verwenden zu lassen? Es könnte schnell passieren, dass das Kontingent für diese API überschritten wird. In diesem Fall richten Sie Parameter ein und verwenden sie.

Definieren Sie grundlegende Parameter in der Datei extension.yaml

Beginnen Sie mit der Konvertierung der Elemente, für die Entwickler möglicherweise eine benutzerdefinierte Konfiguration haben. Der erste wären die Parameter XFIELD und YFIELD .

  1. Fügen Sie in der Datei extension.yaml den folgenden Code hinzu, der die Feldparameter XFIELD und YFIELD verwendet. Diese Parameter befinden sich in der zuvor definierten YAML-Eigenschaft params :

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 benennt den Parameter auf eine Weise, die für Sie, den Erweiterungsersteller, sichtbar ist. Verwenden Sie diesen Wert später, wenn Sie die Parameterwerte angeben.
  • label ist eine für den Entwickler lesbare Kennung, die ihm mitteilt, was der Parameter bewirkt.
  • Beschreibung gibt eine detaillierte Beschreibung des Werts. Da dies Markdown unterstützt, kann es auf zusätzliche Dokumentation verweisen oder Wörter hervorheben, die für den Entwickler wichtig sein könnten.
  • Typ definiert den Eingabemechanismus dafür, wie ein Benutzer den Parameterwert festlegen würde. Es gibt viele Typen, darunter string , select , multiSelect , selectResource und secret . Weitere Informationen zu den einzelnen Optionen finden Sie in der Dokumentation .
  • validationRegex schränkt den Entwicklereintrag auf einen bestimmten Regex-Wert ein (im Beispiel basiert es auf den einfachen Richtlinien für Feldnamen, die Sie hier finden ); und wenn das fehlschlägt...
  • validationErrorMessage macht den Entwickler auf den Fehlerwert aufmerksam.
  • Der Standardwert ist der Wert, den der Entwickler hätte, wenn er keinen Text eingegeben hätte.
  • Erforderlich bedeutet, dass der Entwickler keinen Text eingeben muss.
  • Immutable ermöglicht es dem Entwickler, diese Erweiterung zu aktualisieren und diesen Wert zu ändern. In diesem Fall sollte der Entwickler in der Lage sein, Feldnamen zu ändern, wenn sich seine Anforderungen ändern.
  • Beispiel gibt eine Vorstellung davon, wie eine gültige Eingabe aussehen könnte.

Das war viel zu verstehen!

  1. Sie müssen der Datei extension.yaml drei weitere Parameter hinzufügen, bevor Sie einen speziellen Parameter hinzufügen.
  - 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

Definieren Sie sensible Parameter

Jetzt müssen Sie den vom Benutzer angegebenen API-Schlüssel verwalten. Dies ist eine sensible Zeichenfolge, die in der Funktion nicht im Klartext gespeichert werden sollte. Speichern Sie diesen Wert stattdessen im Cloud Secret Manager . Dabei handelt es sich um einen speziellen Ort in der Cloud, der verschlüsselte Geheimnisse speichert und verhindert, dass diese versehentlich preisgegeben werden. Dies erfordert, dass der Entwickler für die Nutzung dieses Dienstes bezahlt, aber es fügt eine zusätzliche Sicherheitsebene für seine API-Schlüssel hinzu und schränkt möglicherweise betrügerische Aktivitäten ein. Die Benutzerdokumentation weist den Entwickler darauf hin, dass es sich um einen kostenpflichtigen Dienst handelt, sodass es bei der Abrechnung nicht zu Überraschungen kommt. Insgesamt ähnelt die Verwendung den anderen oben genannten String-Ressourcen. Der einzige Unterschied besteht im Typ, der secret genannt wird.

  • Fügen Sie in der Datei extension.yaml den folgenden Code hinzu:

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

Aktualisieren Sie die resource , um Parameter zu verwenden

Wie bereits erwähnt, definiert die Ressource (nicht die Funktion), wie die Ressource beobachtet wird. Daher muss die locationUpdate Ressource aktualisiert werden, um den neuen Parameter verwenden zu können.

  • Fügen Sie in der Datei extension.yaml den folgenden Code hinzu:

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}

Überprüfen Sie die Datei extension.yaml

  • Überprüfen Sie die Datei extension.yaml . Es sollte ungefähr so ​​aussehen:

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.

Zugriffsparameter im Code

Nachdem nun alle Parameter in der Datei extension.yaml konfiguriert sind, fügen Sie sie der Datei index.ts hinzu.

  • Ersetzen Sie in der Datei index.ts die Standardwerte durch process.env.PARAMETER_NAME , wodurch die entsprechenden Parameterwerte abgerufen und in den Funktionscode eingefügt werden, der im Firebase-Projekt des Entwicklers bereitgestellt wird.

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!;

Normalerweise möchten Sie Nullprüfungen mit den Umgebungsvariablenwerten durchführen, aber in diesem Fall vertrauen Sie darauf, dass die Parameterwerte korrekt kopiert werden. Der Code ist nun für die Arbeit mit den Erweiterungsparametern konfiguriert.

7. Erstellen Sie eine Benutzerdokumentation

Bevor der Code auf Emulatoren oder im Firebase-Erweiterungsmarktplatz getestet wird, muss die Erweiterung dokumentiert werden, damit Entwickler wissen, was sie erhalten, wenn sie die Erweiterung verwenden.

  1. Erstellen Sie zunächst die Datei PREINSTALL.md , in der die Funktionalität, etwaige Installationsvoraussetzungen und mögliche Auswirkungen auf die Abrechnung beschrieben werden.

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. Um Zeit beim Schreiben der README.md für dieses Projekt zu sparen, verwenden Sie die praktische Methode:
firebase ext:info . --markdown > README.md

Dadurch werden die Inhalte Ihrer PREINSTALL.md Datei und zusätzliche Details zu Ihrer Erweiterung aus Ihrer extension.yaml Datei kombiniert.

Informieren Sie abschließend den Entwickler der Erweiterung über einige zusätzliche Details zur gerade installierten Erweiterung. Nach Abschluss der Installation erhält der Entwickler möglicherweise einige zusätzliche Anweisungen und Informationen und erhält hier möglicherweise einige detaillierte Aufgaben nach der Installation, wie z. B. das Einrichten des Client-Codes.

  1. Erstellen Sie eine POSTINSTALL.md Datei und fügen Sie dann die folgenden Post-Installationsinformationen hinzu:

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);
  });

Überwachung

Als Best Practice können Sie die Aktivität Ihrer installierten Erweiterung überwachen , einschließlich Überprüfungen des Zustands, der Nutzung und der Protokolle.

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

Dadurch werden die Funktionen neu kompiliert, sodass der neueste Quellcode zusammen mit der Erweiterung für die Bereitstellung bereit ist, wenn diese auf einem Emulator oder direkt in Firebase bereitgestellt wird.

Erstellen Sie als Nächstes ein neues Verzeichnis, um die Erweiterung zu testen. Da die Erweiterung aus vorhandenen Funktionen entwickelt wurde, testen Sie sie nicht in dem Ordner, in dem die Erweiterung konfiguriert wurde, da dieser auch versucht, die Funktionen und Firebase-Regeln parallel bereitzustellen.

Installieren und testen Sie mit den Firebase-Emulatoren

  1. Erstellen Sie ein neues Verzeichnis auf Ihrem Hostsystem und verbinden Sie dieses Verzeichnis mithilfe firebase init mit Ihrem Firebase-Projekt.
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Führen Sie in diesem Verzeichnis firebase ext:install um die Erweiterung zu installieren. Ersetzen Sie /path/to/extension durch den absoluten Pfad zu dem Verzeichnis, das Ihre Datei extension.yaml enthält. Dadurch wird der Installationsprozess für Ihre Erweiterung gestartet und eine .env Datei erstellt, die Ihre Konfigurationen enthält, bevor die Konfiguration an Firebase oder die Emulatoren übertragen wird.
firebase ext:install /path/to/extension
  • Da Sie das Projekt lokal bereitstellen, geben Sie an, dass Sie eine lokale Datei anstelle des Google Cloud Secret Managers verwenden möchten.

da928c65ffa8ce15.png

  1. Starten Sie die lokale Emulator-Suite:
firebase emulators:start

Installieren und testen Sie mit einem echten Firebase-Projekt

Sie können Ihre Erweiterung in einem tatsächlichen Firebase-Projekt installieren. Es wird empfohlen, für Ihre Tests ein Testprojekt zu verwenden. Verwenden Sie diesen Testworkflow, wenn Sie den End-to-End-Ablauf Ihrer Erweiterung testen möchten oder wenn der Trigger Ihrer Erweiterung noch nicht von der Firebase-Emulator-Suite unterstützt wird (siehe die Emulatoroption „Erweiterungen “). Die Emulatoren unterstützen derzeit durch HTTP-Anfragen ausgelöste Funktionen und durch Hintergrundereignisse ausgelöste Funktionen für Cloud Firestore, Realtime Database und Pub/Sub.

  1. Erstellen Sie ein neues Verzeichnis auf Ihrem Hostsystem und verbinden Sie dieses Verzeichnis mithilfe firebase init mit Ihrem Firebase-Projekt.
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Führen Sie dann von diesem Verzeichnis aus firebase ext:install um die Erweiterung zu installieren. Ersetzen Sie /path/to/extension durch den absoluten Pfad zu dem Verzeichnis, das Ihre Datei extension.yaml enthält. Dadurch wird der Installationsprozess für Ihre Erweiterung gestartet und eine .env Datei erstellt, die Ihre Konfigurationen enthält, bevor die Konfiguration an Firebase oder die Emulatoren übertragen wird.
firebase ext:install /path/to/extension
  • Da Sie die Bereitstellung direkt in Firebase durchführen und den Google Cloud Secret Manager verwenden möchten, müssen Sie die Secret Manager-API aktivieren , bevor Sie die Erweiterung installieren.
  1. Stellen Sie es in Ihrem Firebase-Projekt bereit.
firebase deploy

Testen Sie die Erweiterung

  1. Navigieren Sie nach dem Ausführen von firebase deploy oder firebase emulators:start “ zur Registerkarte „Firestore“ entweder der Firebase-Konsole oder der Webansicht der Emulatoren.
  2. Fügen Sie der Sammlung, die durch das x Feld und y Feld angegeben wird, ein Dokument hinzu. In diesem Fall befinden sich aktualisierte Dokumente unter u/{uid} mit einem x Feld von xv und einem y Feld von yv .

Firebase Emulators-Bildschirm zum Hinzufügen eines Firestore-Datensatzes

  1. Wenn Sie die Erweiterung erfolgreich installiert haben, erstellt die Erweiterung im Dokument ein neues Feld namens hash , nachdem Sie die beiden Felder gespeichert haben.

Firestore-Datenbankbildschirm eines Emulators mit hinzugefügtem Hash

8. Herzlichen Glückwunsch!

Sie haben Ihre erste Cloud-Funktion erfolgreich in eine Firebase-Erweiterung umgewandelt!

Sie haben eine Datei extension.yaml hinzugefügt und diese konfiguriert, damit Entwickler auswählen können, wie Ihre Erweiterung bereitgestellt werden soll. Anschließend haben Sie eine Benutzerdokumentation erstellt, die Anleitungen dazu enthält, was die Entwickler der Erweiterung tun sollten, bevor sie die Erweiterung einrichten, und welche Schritte sie nach erfolgreicher Installation der Erweiterung möglicherweise unternehmen müssen.

Sie kennen jetzt die wichtigsten Schritte, die zum Konvertieren einer Firebase-Funktion in eine verteilbare Firebase-Erweiterung erforderlich sind.

Was kommt als nächstes?