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.
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.
- Entpacken Sie die heruntergeladene Zip-Datei.
- Um die erforderlichen Abhängigkeiten zu installieren, öffnen Sie das Terminal im
functions
und führen Sie den Befehlnpm 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.
- 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.
- 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:
- Geben Sie die Lizenz für den Code in Ihrer Erweiterung an.
...
license: Apache-2.0 # The license you want for the extension
- 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
- 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.
- Erstellen Sie in der Datei
extension.yaml
ein Ressourcenobjekt für dielocationUpdate
Funktion. Hängen Sie Folgendes an die Dateiextension.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.
- 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.
- 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!
- Wenn Sie es noch nicht getan haben, rufen Sie
npm run build
im Funktionsordner des heruntergeladenen Erweiterungsprojekts auf. - 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.
- Führen Sie im selben Verzeichnis
firebase ext:install
. Ersetzen Sie/path/to/extension
durch den absoluten Pfad zu dem Verzeichnis, das Ihre Dateiextension.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
Ihrerfirebase.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.
- Starten Sie die Firebase-Emulatoren mit der neuen Konfiguration:
firebase emulators:start
- Navigieren Sie nach dem Ausführen
emulators:start
zur Registerkarte Firestore in der Webansicht der Emulatoren. - Fügen Sie der
users
ein Dokument mit einemxv
-Nummernfeld undyv
-Nummernfeld hinzu.
- Wenn Sie die Erweiterung erfolgreich installiert haben, erstellt die Erweiterung ein neues Feld namens
hash
im Dokument.
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
.
- Fügen Sie in der Datei
extension.yaml
den folgenden Code hinzu, der die FeldparameterXFIELD
undYFIELD
verwendet. Diese Parameter befinden sich in der zuvor definierten YAML-Eigenschaftparams
:
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
undsecret
. 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!
- 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 durchprocess.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.
- 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)
- 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.
- 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
- 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
- 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 Dateiextension.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.
- 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.
- 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
- 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 Dateiextension.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.
- Stellen Sie es in Ihrem Firebase-Projekt bereit.
firebase deploy
Testen Sie die Erweiterung
- Navigieren Sie nach dem Ausführen von
firebase deploy
oderfirebase emulators:start
“ zur Registerkarte „Firestore“ entweder der Firebase-Konsole oder der Webansicht der Emulatoren. - Fügen Sie der Sammlung, die durch das
x
Feld undy
Feld angegeben wird, ein Dokument hinzu. In diesem Fall befinden sich aktualisierte Dokumente unteru/{uid}
mit einemx
Feld vonxv
und einemy
Feld vonyv
.
- Wenn Sie die Erweiterung erfolgreich installiert haben, erstellt die Erweiterung im Dokument ein neues Feld namens
hash
, nachdem Sie die beiden Felder gespeichert haben.
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.