1. Zanim zaczniesz
Rozszerzenie Firebase wykonuje określone zadanie lub zestaw zadań w odpowiedzi na żądania HTTP lub zdarzenia wywołujące z innych usług Firebase i Google, takich jak Komunikacja w chmurze Firebase, Cloud Firestore czy Pub/Sub.
Co utworzysz
W tym ćwiczeniu utworzysz rozszerzenie Firebase do geohashingu. Po wdrożeniu rozszerzenie przekształca współrzędne X i Y w geohashe w odpowiedzi na zdarzenia Firestore lub wywołania funkcji, które można wywołać. Możesz użyć tej metody zamiast wdrażać bibliotekę geofire na wszystkich platformach docelowych do przechowywania danych, co pozwoli Ci zaoszczędzić czas.
Czego się nauczysz
- Jak przekształcić istniejący kod Cloud Functions w rozszerzenie Firebase do rozpowszechniania
- Jak skonfigurować plik
extension.yaml
- Jak przechowywać w rozszerzeniu ciągi znaków zawierające informacje poufne (klucze interfejsu API)
- Jak umożliwić deweloperom rozszerzenia skonfigurowanie go zgodnie z ich potrzebami
- Jak przetestować i wdrożyć rozszerzenie
Czego potrzebujesz
- Wiersz poleceń Firebase (instalacja i logowanie)
- konto Google, np. konto Gmail;
- Node.js i
npm
- Twoje ulubione środowisko programistyczne
2. Pierwsze kroki
Pobierz kod
Wszystko, czego potrzebujesz do tego rozszerzenia, znajdziesz w repozytorium GitHub. Aby rozpocząć, pobierz kod i otwórz go w ulubionym środowisku programistycznym.
- Rozpakuj pobrany plik ZIP.
- Aby zainstalować wymagane zależności, otwórz terminal w katalogu
functions
i uruchom polecenienpm install
.
Konfigurowanie Firebase
W tym samouczku zdecydowanie zalecamy używanie emulatorów Firebase. Jeśli chcesz wypróbować tworzenie rozszerzeń w prawdziwym projekcie Firebase, zapoznaj się z artykułem tworzenie projektu Firebase. W tym laboratorium używamy Cloud Functions, więc jeśli korzystasz z prawdziwego projektu Firebase zamiast emulatorów, musisz przejść na abonament Blaze.
Chcesz pominąć ten krok?
Możesz pobrać ukończoną wersję codelabu. Jeśli napotkasz trudności lub chcesz zobaczyć, jak wygląda gotowe rozszerzenie, sprawdź gałąź codelab-end
w repozytorium GitHub lub pobierz gotowy plik ZIP.
3. Sprawdź kod
- Otwórz plik
index.ts
z pliku ZIP. Zwróć uwagę, że zawiera on 2 deklaracje funkcji w Cloud Functions.
Do czego służą te funkcje?
Te funkcje demonstracyjne są używane do geohashingu. Pobierają parę współrzędnych i przekształcają ją w format zoptymalizowany pod kątem zapytań geograficznych w Firestore. Funkcje te symulują użycie wywołania interfejsu API, dzięki czemu możesz dowiedzieć się więcej o obsłudze typów danych wrażliwych w rozszerzeniach. Więcej informacji znajdziesz w dokumentacji na temat uruchamiania zapytań geograficznych dotyczących danych w Firestore.
Stałe funkcji
Stałe są deklarowane na początku pliku index.ts
, u góry. Niektóre z tych stałych są używane w określonych w rozszerzeniu regułach.
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);
Aktywator Firestore
Pierwsza funkcja w pliku index.ts
wygląda tak:
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,
}
);
});
Ta funkcja to wyzwalacz Firestore. Gdy w bazie danych wystąpi zdarzenie zapisu, funkcja reaguje na nie, wyszukując pola xv
i yv
. Jeśli oba te pola istnieją, oblicza geohash i zapisuje wynik w określonej lokalizacji dokumentu wyjściowego. Dokument wejściowy jest zdefiniowany przez stałą users/{uid}
, co oznacza, że funkcja odczytuje każdy dokument zapisany w kolekcji users/
, a następnie przetwarza geohash dla tych dokumentów. Następnie zapisuje identyfikator w polu identyfikatora w tym samym dokumencie.
Funkcje wywoływane
Kolejna funkcja w pliku index.ts
wygląda tak:
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};
});
Zwróć uwagę na funkcję onCall
. Oznacza to, że funkcja jest funkcją wywoływalną, którą można wywołać z kodu aplikacji klienckiej. Ta funkcja wywoływana przyjmuje parametry x
i y
oraz zwraca geohash. Chociaż ta funkcja nie będzie wywoływana bezpośrednio w tym laboratorium, jest tu uwzględniona jako przykład elementu do skonfigurowania w rozszerzeniu Firebase.
4. Konfigurowanie pliku extension.yaml
Teraz, gdy wiesz już, co robi kod Cloud Functions w Twoim rozszerzeniu, możesz go spakować i rozpowszechnić. Każde rozszerzenie Firebase ma plik extension.yaml
, który opisuje, co robi rozszerzenie i jak działa.
Plik extension.yaml
wymaga początkowych metadanych rozszerzenia. Każdy z tych kroków pomoże Ci zrozumieć, co oznaczają poszczególne pola i dlaczego są potrzebne.
- Utwórz plik
extension.yaml
w katalogu głównym pobranego wcześniej projektu. Zacznij od dodania tych elementów:
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
Nazwa rozszerzenia jest używana jako podstawa identyfikatora instancji rozszerzenia (użytkownicy mogą instalować wiele instancji rozszerzenia, z których każda ma własny identyfikator). Firebase wygeneruje wtedy nazwy kont usługi rozszerzenia i zasobów specyficznych dla rozszerzenia, używając tego identyfikatora instancji. Numer wersji wskazuje wersję rozszerzenia. Musi ona być zgodna z semantycznym numerowaniem wersji i musisz ją aktualizować za każdym razem, gdy wprowadzasz zmiany w funkcjonalności rozszerzenia. Wersja specyfikacji rozszerzenia służy do określania, której specyfikacji rozszerzeń Firebase należy użyć. W tym przypadku jest to v1beta
.
- Dodaj do pliku YAML kilka informacji, które będą przydatne dla użytkowników:
...
displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.
Wyświetlana nazwa to przyjazna reprezentacja nazwy rozszerzenia, która jest widoczna, gdy deweloperzy wchodzą z nim w interakcję. Opis zawiera krótki przegląd działania rozszerzenia. Gdy rozszerzenie zostanie wdrożone na stronie extensions.dev, będzie wyglądać mniej więcej tak:
- Określ licencję na kod w rozszerzeniu.
...
license: Apache-2.0 # The license you want for the extension
- Określ, kto napisał rozszerzenie, i czy do jego zainstalowania wymagane jest rozliczenie:
...
author:
authorName: AUTHOR_NAME
url: https://github.com/Firebase
billingRequired: true
Sekcja author
służy do informowania użytkowników, z kim mogą się skontaktować, jeśli mają problemy z rozszerzeniem lub chcą uzyskać więcej informacji na jego temat. billingRequired
to wymagany parametr, który musi mieć wartość true
, ponieważ wszystkie rozszerzenia korzystają z Cloud Functions, co wymaga abonamentu Blaze.
Obejmuje to minimalną liczbę pól wymaganych w pliku extension.yaml
do identyfikacji tego rozszerzenia. Więcej informacji o innych informacjach identyfikacyjnych, które możesz określić w rozszerzeniu, znajdziesz w dokumentacji.
5. Konwertowanie kodu Cloud Functions na zasób rozszerzenia
Zasób rozszerzenia to element, który Firebase tworzy w projekcie podczas instalacji rozszerzenia. Rozszerzenie staje się właścicielem tych zasobów i ma określone konto usługi, które na nich działa. W tym projekcie są to funkcje Cloud Functions, które muszą być zdefiniowane w pliku extension.yaml
, ponieważ rozszerzenie nie utworzy automatycznie zasobów z kodu w folderze funkcji. Jeśli funkcje Cloud Functions nie są wyraźnie zadeklarowane jako zasób, nie można ich wdrożyć podczas wdrażania rozszerzenia.
Lokalizacja wdrożenia zdefiniowana przez użytkownika
- Umożliwia użytkownikowi określenie lokalizacji, w której chce wdrożyć to rozszerzenie, i podjęcie decyzji, czy lepiej będzie hostować rozszerzenie bliżej użytkowników, czy bliżej bazy danych. W pliku
extension.yaml
uwzględnij opcję wyboru lokalizacji.
extension.yaml
Możesz teraz napisać konfigurację zasobu funkcji.
- W pliku
extension.yaml
utwórz obiekt zasobu dla funkcjilocationUpdate
. Dodaj do plikuextension.yaml
te wiersze:
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
to nazwa funkcji zdefiniowana w pliku index.ts
projektu. Określasz type
wdrażanej funkcji, która na razie powinna zawsze mieć wartość firebaseextensions.v1beta.function
. Następnie zdefiniuj properties
tej funkcji. Pierwszą właściwością, którą zdefiniujesz, jest eventTrigger
powiązany z tą funkcją. Aby odzwierciedlić to, co obecnie obsługuje rozszerzenie, użyj eventType
funkcji providers/cloud.firestore/eventTypes/document.write
, którą znajdziesz w dokumentacji Pisanie funkcji Cloud Functions dla rozszerzenia. resource
określasz jako lokalizację dokumentów. Ponieważ Twoim obecnym celem jest odzwierciedlenie tego, co znajduje się w kodzie, ścieżka dokumentu nasłuchuje users/{uid}
, a przed nią znajduje się domyślna lokalizacja bazy danych.
- Rozszerzenie potrzebuje uprawnień do odczytu i zapisu w bazie danych Firestore. Na samym końcu pliku
extension.yaml
określ role IAM, do których rozszerzenie powinno mieć dostęp, aby pracować z bazą danych w projekcie Firebase dewelopera.
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
Rola datastore.user
pochodzi z listy obsługiwanych ról uprawnień w przypadku rozszerzeń. Rozszerzenie będzie odczytywać i zapisywać dane, więc rola datastore.user
będzie w tym przypadku odpowiednia.
- Należy też dodać funkcję wywoływaną. W pliku
extension.yaml
utwórz nowy zasób we właściwości resources. Te właściwości są specyficzne dla funkcji wywoływanej:
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
W poprzednim zasobie użyto znaku eventTrigger
, a tutaj używasz znaku httpsTrigger
, który obejmuje zarówno funkcje wywoływane, jak i funkcje HTTPS.
Sprawdzanie kodu
Wymagało to sporo konfiguracji, aby extension.yaml
pasowało do wszystkiego, co robi kod w pliku index.ts
. W tym momencie ukończony plik extension.yaml
powinien wyglądać tak:
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.
Sprawdzanie stanu
Na tym etapie masz już skonfigurowane początkowe funkcjonalne elementy rozszerzenia, więc możesz je wypróbować za pomocą emulatorów Firebase.
- Jeśli jeszcze tego nie zrobiono, wywołaj funkcję
npm run build
w folderze funkcji pobranego projektu rozszerzeń. - Utwórz nowy katalog w systemie hosta i połącz go z projektem Firebase za pomocą
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.
- W tym samym katalogu uruchom
firebase ext:install
. Zastąp/path/to/extension
ścieżką bezwzględną do katalogu, który zawiera plikextension.yaml
.
firebase ext:install /path/to/extension
This command does two things:
- Poprosi Cię o określenie konfiguracji instancji rozszerzenia i utworzy plik
*.env
zawierający informacje o konfiguracji instancji. - Spowoduje to dodanie instancji rozszerzenia do sekcji
extensions
na stroniefirebase.json
. Działa to jak mapa identyfikatorów instancji do wersji rozszerzenia. - Ponieważ wdrażasz projekt lokalnie, możesz określić, że chcesz używać pliku lokalnego zamiast usługi Google Cloud Secret Manager.
- Uruchom emulatory Firebase z nową konfiguracją:
firebase emulators:start
- Po uruchomieniu
emulators:start
otwórz kartę Firestore w widoku internetowym emulatorów. - Dodaj dokument do kolekcji
users
z polem liczbowymxv
i polem liczbowymyv
.
- Jeśli instalacja rozszerzenia się powiedzie, w dokumencie pojawi się nowe pole o nazwie
hash
.
Czyszczenie, aby uniknąć konfliktów
- Po zakończeniu testowania odinstaluj rozszerzenie, ponieważ będziesz aktualizować jego kod i nie chcesz, aby w przyszłości doszło do konfliktu z obecnym rozszerzeniem.
Rozszerzenia umożliwiają zainstalowanie kilku wersji tego samego rozszerzenia jednocześnie, więc odinstalowanie zapewnia brak konfliktów z wcześniej zainstalowanym rozszerzeniem.
firebase ext:uninstall geohash-ext
Obecne rozwiązanie działa, ale jak wspomniano na początku projektu, jest w nim zakodowany klucz interfejsu API, który symuluje komunikację z usługą. Jak używać klucza interfejsu API użytkownika zamiast klucza dostarczonego pierwotnie? Czytaj dalej, aby się dowiedzieć.
6. Umożliwianie użytkownikom konfigurowania rozszerzenia
Na tym etapie samouczka masz rozszerzenie skonfigurowane do używania z opartą na opiniach konfiguracją funkcji, które zostały już napisane. Co jednak, jeśli użytkownik chce używać szerokości i długości geograficznej zamiast y i x w polach wskazujących lokalizację na płaszczyźnie kartezjańskiej? Jak możesz też sprawić, aby użytkownik podawał własny klucz interfejsu API, zamiast korzystać z dostarczonego klucza? Możesz szybko przekroczyć limit tego interfejsu API. W tym przypadku konfigurujesz i używasz parametrów.
Określ podstawowe parametry w extension.yaml
pliku.
Zacznij od przekonwertowania elementów, dla których deweloperzy mogą mieć niestandardową konfigurację. Pierwsze to parametry XFIELD
i YFIELD
.
- W pliku
extension.yaml
dodaj ten kod, który korzysta z parametrów pólXFIELD
iYFIELD
. Te parametry znajdują się w zdefiniowanej wcześniej właściwości YAMLparams
:
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 nadaje parametrowi nazwę widoczną dla Ciebie, czyli producenta rozszerzenia. Użyj tej wartości później, gdy będziesz określać wartości parametrów.
- label to identyfikator czytelny dla dewelopera, który informuje go o tym, do czego służy parametr.
- Tag description zawiera szczegółowy opis wartości. Obsługuje on format Markdown, więc może zawierać linki do dodatkowej dokumentacji lub wyróżniać słowa, które mogą być ważne dla dewelopera.
- Atrybut type określa mechanizm wprowadzania, za pomocą którego użytkownik może ustawić wartość parametru. Istnieje wiele typów, m.in.
string
,select
,multiSelect
,selectResource
isecret
. Więcej informacji o każdej z tych opcji znajdziesz w dokumentacji. - validationRegex ogranicza wpis dewelopera do określonej wartości wyrażenia regularnego (w przykładzie jest to oparte na prostych wytycznych dotyczących nazw pól znajdujących się tutaj); a jeśli to się nie uda...
- validationErrorMessage informuje dewelopera o wartości błędu.
- default to wartość, która byłaby używana, gdyby deweloper nie wpisał żadnego tekstu.
- Wymagane oznacza, że deweloper nie musi wpisywać żadnego tekstu.
- immutable umożliwia deweloperowi aktualizowanie tego rozszerzenia i zmianę tej wartości. W takim przypadku deweloper powinien mieć możliwość zmiany nazw pól w miarę zmieniających się wymagań.
- Przykład pokazuje, jak mogą wyglądać prawidłowe dane wejściowe.
To było trudne do zrozumienia.
- Zanim dodasz parametr specjalny, musisz dodać do pliku
extension.yaml
jeszcze 3 parametry.
- 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
Określanie parametrów o charakterze kontrowersyjnym
Teraz musisz zarządzać kluczem interfejsu API określonym przez użytkownika. Jest to ciąg znaków zawierający informacje poufne, które nie powinny być przechowywane w funkcji w postaci zwykłego tekstu. Zamiast tego zapisz tę wartość w usłudze Cloud Secret Manager. Jest to specjalna lokalizacja w chmurze, w której przechowywane są zaszyfrowane obiekty tajne, co zapobiega ich przypadkowemu wyciekowi. Wymaga to od dewelopera opłaty za korzystanie z tej usługi, ale zapewnia dodatkową warstwę zabezpieczeń kluczy interfejsu API i potencjalnie ogranicza nieuczciwe działania. Dokumentacja użytkownika informuje dewelopera, że jest to usługa płatna, dzięki czemu nie będzie żadnych niespodzianek w rozliczeniach. Ogólnie rzecz biorąc, użycie jest podobne do innych zasobów ciągów znaków wymienionych powyżej. Jedyną różnicą jest typ o nazwie secret
.
- W pliku
extension.yaml
dodaj ten kod:
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
Zaktualizuj resource
atrybuty, aby używać parametrów
Jak wspomnieliśmy wcześniej, sposób obserwacji zasobu określa sam zasób (a nie funkcja), więc aby używać nowego parametru, należy zaktualizować locationUpdate
zasób.
- W pliku
extension.yaml
dodaj ten kod:
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}
Sprawdź plik extension.yaml
- Sprawdź plik
extension.yaml
. Powinna wyglądać mniej więcej tak:
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.
Dostęp do parametrów w kodzie
Teraz, gdy wszystkie parametry są skonfigurowane w pliku extension.yaml
, dodaj je do pliku index.ts
.
- W pliku
index.ts
zastąp wartości domyślne wartościąprocess.env.PARAMETER_NAME
, która pobiera odpowiednie wartości parametrów i wypełnia nimi kod funkcji wdrożony w projekcie Firebase dewelopera.
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!;
Zwykle warto sprawdzać, czy wartości zmiennych środowiskowych nie są wartościami null, ale w tym przypadku możesz założyć, że wartości parametrów są prawidłowo kopiowane. Kod jest teraz skonfigurowany do współpracy z parametrami rozszerzenia.
7. Tworzenie dokumentacji użytkownika
Zanim przetestujesz kod na emulatorach lub w usłudze Firebase Extensions Marketplace, musisz udokumentować rozszerzenie, aby deweloperzy wiedzieli, co otrzymają, gdy go użyją.
- Zacznij od utworzenia pliku
PREINSTALL.md
, który służy do opisywania funkcji, wszelkich wymagań wstępnych dotyczących instalacji i potencjalnych konsekwencji związanych z płatnościami.
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)
- Aby zaoszczędzić czas na pisaniu
README.md
dla tego projektu, użyj wygodnej metody:
firebase ext:info . --markdown > README.md
Łączy on zawartość pliku PREINSTALL.md
z dodatkowymi szczegółami rozszerzenia z pliku extension.yaml
.
Na koniec poinformuj dewelopera rozszerzenia o dodatkowych szczegółach dotyczących właśnie zainstalowanego rozszerzenia. Po zakończeniu instalacji deweloper może otrzymać dodatkowe instrukcje i informacje, a także szczegółowe zadania do wykonania po instalacji, takie jak skonfigurowanie kodu klienta.
- Utwórz plik
POSTINSTALL.md
i dodaj do niego te informacje po instalacji:
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);
});
Monitorowanie
Zalecamy monitorowanie aktywności zainstalowanego rozszerzenia, w tym sprawdzanie jego stanu, użycia i logów.
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
Spowoduje to ponowną kompilację funkcji, dzięki czemu najnowszy kod źródłowy będzie gotowy do wdrożenia wraz z rozszerzeniem na emulatorze lub bezpośrednio w Firebase.
Następnie utwórz nowy katalog, w którym będziesz testować rozszerzenie. Rozszerzenie zostało opracowane na podstawie istniejących funkcji, więc nie testuj go w folderze, w którym zostało skonfigurowane, ponieważ spowoduje to również próbę wdrożenia funkcji i reguł Firebase.
Instalowanie i testowanie za pomocą emulatorów Firebase
- Utwórz nowy katalog w systemie hosta i połącz go z projektem Firebase za pomocą
firebase init
.
mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- W tym katalogu uruchom
firebase ext:install
, aby zainstalować rozszerzenie. Zastąp/path/to/extension
ścieżką bezwzględną do katalogu, który zawiera plikextension.yaml
. Spowoduje to rozpoczęcie procesu instalacji rozszerzenia i utworzenie pliku.env
zawierającego konfiguracje przed przesłaniem konfiguracji do Firebase lub emulatorów.
firebase ext:install /path/to/extension
- Ponieważ wdrażasz projekt lokalnie, wskaż, że chcesz użyć pliku lokalnego zamiast usługi Google Cloud Secret Manager.
- Uruchom lokalny pakiet emulatorów:
firebase emulators:start
Instalowanie i testowanie w rzeczywistym projekcie Firebase
Rozszerzenie możesz zainstalować w rzeczywistym projekcie Firebase. Do testowania zalecamy używanie projektu testowego. Skorzystaj z tej instrukcji testowania, jeśli chcesz przetestować cały proces rozszerzenia lub jeśli wyzwalacz rozszerzenia nie jest jeszcze obsługiwany przez pakiet emulatorów Firebase (patrz Opcja emulatora rozszerzeń). Obecnie emulatory obsługują funkcje aktywowane przez żądania HTTP oraz funkcje aktywowane przez zdarzenia w tle w przypadku Cloud Firestore, Bazy danych czasu rzeczywistego i Pub/Sub.
- Utwórz nowy katalog w systemie hosta i połącz go z projektem Firebase za pomocą
firebase init
.
cd .. mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- Następnie w tym katalogu uruchom polecenie
firebase ext:install
, aby zainstalować rozszerzenie. Zastąp/path/to/extension
ścieżką bezwzględną do katalogu, który zawiera plikextension.yaml
. Spowoduje to rozpoczęcie procesu instalacji rozszerzenia i utworzenie pliku.env
zawierającego konfiguracje przed przesłaniem konfiguracji do Firebase lub emulatorów.
firebase ext:install /path/to/extension
- Jeśli chcesz wdrożyć rozszerzenie bezpośrednio w Firebase i używać Google Cloud Secret Manager, przed zainstalowaniem rozszerzenia musisz aktywować interfejs Secret Manager API.
- Wdróż w projekcie Firebase.
firebase deploy
Testowanie rozszerzenia
- Po uruchomieniu polecenia
firebase deploy
lubfirebase emulators:start
otwórz kartę Firestore w konsoli Firebase lub w widoku internetowym emulatorów. - Dodaje dokument do kolekcji określonej przez pole
x
i poley
. W tym przypadku zaktualizowane dokumenty znajdują się wu/{uid}
, a polex
ma wartośćxv
, a poley
ma wartośćyv
.
- Jeśli instalacja rozszerzenia się powiedzie, po zapisaniu 2 pól w dokumencie pojawi się nowe pole o nazwie
hash
.
8. Gratulacje!
Udało Ci się przekształcić pierwszą funkcję Cloud Functions w rozszerzenie Firebase.
Dodano plik extension.yaml
i skonfigurowano go tak, aby deweloperzy mogli wybrać sposób wdrażania rozszerzenia. Następnie utworzono dokumentację użytkownika, która zawiera wskazówki dla deweloperów rozszerzenia dotyczące tego, co powinni zrobić przed skonfigurowaniem rozszerzenia, oraz jakie kroki mogą być konieczne po jego pomyślnej instalacji.
Znasz już najważniejsze kroki wymagane do przekształcenia Funkcji Firebase w rozpowszechniane rozszerzenie Firebase.