Menggunakan kembali kode Cloud Functions sebagai Firebase Extensions

1. Sebelum memulai

Firebase Extensions menjalankan tugas atau serangkaian tugas tertentu sebagai respons terhadap permintaan HTTP atau peristiwa pemicu dari produk Firebase dan Google lainnya seperti Firebase Cloud Messaging, Cloud Firestore, atau Pub/Sub.

Hal yang akan Anda build

Dalam codelab ini, Anda akan mem-build ekstensi Firebase untuk geohashing. Setelah di-deploy, ekstensi Anda kemudian mengonversi koordinat X dan Y menjadi geohash sebagai respons terhadap peristiwa Firestore atau melalui pemanggilan fungsi callable. Hal ini dapat digunakan sebagai alternatif untuk mengimplementasikan library geofire di semua platform target untuk menyimpan data, sehingga menghemat waktu Anda.

Ekstensi geohash yang ditampilkan di Firebase console

Hal yang akan Anda pelajari

  • Cara mengambil kode Cloud Functions yang ada dan mengubahnya menjadi Firebase Extensions yang dapat didistribusikan
  • Cara menyiapkan file extension.yaml
  • Cara menyimpan string sensitif (kunci API) dalam ekstensi
  • Cara mengizinkan developer ekstensi untuk mengonfigurasinya agar sesuai dengan kebutuhan mereka
  • Cara menguji dan men-deploy ekstensi

Hal yang akan Anda perlukan

  • Firebase CLI (penginstalan dan login)
  • Akun Google, seperti akun gmail
  • Node.js dan npm
  • Lingkungan pengembangan favorit Anda

2. Memulai persiapan

Mendapatkan kode

Semua yang Anda perlukan untuk ekstensi ini ada dalam repo GitHub. Untuk memulai, ambil kode dan buka di lingkungan pengembangan favorit Anda.

  1. Mengekstrak file zip yang didownload.
  2. Untuk menginstal dependensi yang diperlukan, buka terminal di direktori functions dan jalankan perintah npm install.

Menyiapkan Firebase

Codelab ini sangat mendorong penggunaan emulator Firebase. Jika Anda ingin mencoba pengembangan ekstensi dengan project Firebase sungguhan, lihat membuat project Firebase. Codelab ini menggunakan Cloud Functions. Jadi, jika Anda menggunakan project Firebase sungguhan, bukan emulator, Anda perlu mengupgrade ke paket harga Blaze.

Ingin melewatinya?

Anda dapat mendownload versi codelab yang sudah selesai. Jika Anda mengalami kesulitan atau ingin melihat tampilan ekstensi yang telah selesai, lihat cabang codelab-end dari repositori GitHub atau download zip yang sudah selesai.

3. Meninjau kode

  • Buka file index.ts dari file ZIP. Perhatikan bahwa skrip tersebut berisi dua deklarasi Cloud Functions di dalamnya.

Apa fungsi fungsi tersebut?

Fungsi demo ini digunakan untuk melakukan geohashing. Mereka mengambil pasangan koordinat dan mengubahnya menjadi format yang dioptimalkan untuk kueri geografis di Firestore. Fungsi tersebut menyimulasikan penggunaan panggilan API sehingga Anda dapat mempelajari lebih lanjut cara menangani jenis data sensitif di ekstensi. Untuk mengetahui informasi selengkapnya, lihat dokumentasi tentang menjalankan kueri Geografis pada data di Firestore.

Konstanta fungsi

Konstanta dideklarasikan sejak awal, di bagian atas file index.ts. Beberapa konstanta ini direferensikan dalam pemicu yang ditentukan oleh ekstensi.

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

Pemicu Firestore

Fungsi pertama dalam file index.ts terlihat seperti ini:

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

Fungsi ini adalah pemicu Firestore. Saat peristiwa tulis terjadi di database, fungsi tersebut akan bereaksi terhadap peristiwa tersebut dengan menelusuri kolom xv dan kolom yv. Selain itu, jika kedua kolom tersebut ada, fungsi tersebut akan menghitung geohash dan menulis output ke lokasi output dokumen yang ditentukan. Dokumen input ditentukan oleh konstanta users/{uid}, yang berarti bahwa fungsi tersebut membaca setiap dokumen yang ditulis ke koleksi users/, lalu memproses geohash untuk dokumen tersebut. Kemudian membuat {i>hash<i} ke sebuah kolom {i>hash<i} dalam dokumen yang sama.

Fungsi Callable

Fungsi berikutnya dalam file index.ts akan terlihat seperti ini:

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

Perhatikan fungsi onCall. Hal tersebut menunjukkan bahwa fungsi ini adalah fungsi callable, yang dapat dipanggil dari dalam kode aplikasi klien Anda. Fungsi callable ini menggunakan parameter x dan y serta menampilkan geohash. Meskipun tidak akan dipanggil langsung dalam codelab ini, fungsi ini disertakan di sini sebagai contoh sesuatu yang harus dikonfigurasi dalam ekstensi Firebase.

4. Siapkan file ekstensi.yaml

Setelah mengetahui fungsi kode Cloud Functions di ekstensi, Anda siap mengemasnya untuk didistribusikan. Setiap ekstensi Firebase dilengkapi dengan file extension.yaml yang menjelaskan fungsi ekstensi dan perilakunya.

File extension.yaml memerlukan beberapa metadata awal tentang ekstensi Anda. Setiap langkah berikut membantu Anda memahami arti semua kolom dan alasan Anda memerlukannya.

  1. Buat file extension.yaml di direktori utama project yang telah Anda download sebelumnya. Mulailah dengan menambahkan hal-hal berikut:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

Nama ekstensi digunakan sebagai dasar ID instance ekstensi (pengguna dapat menginstal beberapa instance ekstensi, masing-masing dengan ID-nya sendiri). Firebase kemudian membuat nama akun layanan ekstensi dan resource khusus ekstensi menggunakan ID instance tersebut. Nomor versi menunjukkan versi ekstensi Anda. Versi tersebut harus mengikuti pembuatan versi semantik, dan Anda harus memperbaruinya setiap kali melakukan perubahan pada fungsi ekstensi. Versi spesifikasi ekstensi digunakan untuk menentukan spesifikasi ekstensi Firebase yang harus diikuti, dalam hal ini, v1beta yang digunakan.

  1. Tambahkan beberapa detail yang mudah digunakan ke file YAML:
...

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

Nama tampilan adalah representasi nama ekstensi yang sesuai saat developer berinteraksi dengan ekstensi Anda. Deskripsi memberikan ringkasan singkat tentang fungsi ekstensi. Saat ekstensi di-deploy di extensions.dev, ekstensi akan terlihat seperti ini:

Ekstensi Konverter Geohash seperti yang terlihat di extensions.dev

  1. Tentukan lisensi untuk kode dalam ekstensi Anda.
...

license: Apache-2.0  # The license you want for the extension
  1. Tunjukkan siapa yang menulis ekstensi dan apakah ekstensi tersebut memerlukan penagihan atau tidak:
...

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

billingRequired: true

Bagian author digunakan untuk memberi tahu pengguna siapa yang harus dihubungi jika mereka mengalami masalah dengan ekstensi atau ingin mendapatkan informasi lebih lanjut tentang ekstensi tersebut. billingRequired adalah parameter wajib dan harus ditetapkan ke true karena semua ekstensi mengandalkan Cloud Functions, yang memerlukan paket Blaze.

Ini mencakup jumlah minimum kolom yang diperlukan dalam file extension.yaml untuk mengidentifikasi ekstensi ini. Untuk detail selengkapnya tentang informasi identitas lainnya yang dapat Anda tentukan dalam ekstensi, lihat dokumentasi.

5. Mengonversi kode Cloud Functions menjadi resource Extensions

Resource ekstensi adalah item yang dibuat Firebase di project selama penginstalan ekstensi. Ekstensi kemudian memiliki resource tersebut dan memiliki akun layanan tertentu yang beroperasi di resource tersebut. Dalam project ini, resource tersebut adalah Cloud Functions, yang harus ditentukan dalam file extension.yaml karena ekstensi tidak akan otomatis membuat resource dari kode di folder fungsi. Jika Cloud Functions Anda tidak dideklarasikan secara eksplisit sebagai resource, fungsi tersebut tidak dapat di-deploy saat ekstensi di-deploy.

Lokasi deployment yang ditentukan pengguna

  1. Izinkan pengguna menentukan lokasi tempat mereka ingin men-deploy ekstensi ini dan memutuskan apakah akan lebih baik untuk menghosting ekstensi lebih dekat dengan pengguna akhir atau lebih dekat ke database mereka. Di file extension.yaml, sertakan opsi untuk memilih lokasi.

extension.yaml

Sekarang Anda siap menulis konfigurasi untuk resource fungsi.

  1. Di file extension.yaml, buat objek resource untuk fungsi locationUpdate. Tambahkan kode berikut ke file extension.yaml:
resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}

Anda menentukan name sebagai nama fungsi yang ditentukan dalam file index.ts project. Anda menentukan type fungsi yang sedang di-deploy, yang seharusnya selalu firebaseextensions.v1beta.function, untuk saat ini. Lalu, tentukan properties fungsi ini. properti pertama yang Anda tentukan adalah eventTrigger yang dikaitkan dengan fungsi ini. Untuk mencerminkan apa yang saat ini didukung ekstensi, Anda menggunakan eventType dari providers/cloud.firestore/eventTypes/document.write, yang tersedia dalam dokumentasi Menulis Cloud Functions untuk ekstensi Anda. Anda menentukan resource sebagai lokasi dokumen. Karena sasaran Anda saat ini adalah mencerminkan apa yang ada dalam kode, jalur dokumen akan memproses users/{uid}, dengan lokasi database default sebelumnya.

  1. Ekstensi memerlukan izin baca dan tulis untuk database Firestore. Di bagian paling akhir file extension.yaml, tentukan peran IAM yang dapat diakses ekstensi untuk bekerja dengan database dalam project Firebase developer.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Peran datastore.user berasal dari daftar peran IAM yang didukung untuk ekstensi. Karena ekstensinya adalah membaca dan menulis, peran datastore.user cocok di sini.

  1. Fungsi callable juga harus ditambahkan. Di file extension.yaml, buat resource baru di bagian properti resource. Properti ini khusus untuk fungsi callable:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

Meskipun resource sebelumnya menggunakan eventTrigger, di sini Anda menggunakan httpsTrigger yang mencakup fungsi callable dan fungsi HTTPS.

Pemeriksaan kode

Begitu banyak konfigurasi untuk membuat extension.yaml Anda cocok dengan semua yang dilakukan oleh kode di file index.ts Anda. Seperti inilah tampilan file extension.yaml yang telah selesai saat ini:

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.

Pemeriksaan status

Pada tahap ini, Anda telah menyiapkan bagian fungsional awal dari ekstensi sehingga Anda dapat benar-benar mencobanya menggunakan emulator Firebase.

  1. Jika Anda belum melakukannya, panggil npm run build di folder fungsi dari project ekstensi yang didownload.
  2. Buat direktori baru di sistem host dan hubungkan direktori tersebut ke project Firebase Anda menggunakan firebase init.
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
    This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
  1. Dari direktori yang sama, jalankan firebase ext:install. Ganti /path/to/extension dengan jalur absolut ke direktori yang berisi file extension.yaml Anda.
firebase ext:install /path/to/extension
    This command does two things:
  • Fungsi ini meminta Anda untuk menentukan konfigurasi untuk instance ekstensi, dan akan membuat file *.env yang berisi informasi konfigurasi untuk instance tersebut.
  • Tindakan ini akan menambahkan instance ekstensi ke bagian extensions dari firebase.json Anda. Ini berfungsi sebagai peta ID instance ke versi ekstensi.
  • Karena men-deploy project secara lokal, Anda dapat menentukan apakah ingin menggunakan file lokal, bukan Google Cloud Secret Manager.

Screenshot proses penginstalan ekstensi yang menunjukkan bahwa file Lokal digunakan untuk secret saat menginstal ekstensi ini

  1. Mulai emulator Firebase dengan konfigurasi baru:
firebase emulators:start
  1. Setelah menjalankan emulators:start, buka tab Firestore di webview emulator.
  2. Tambahkan dokumen ke dalam koleksi users dengan kolom angka xv dan kolom angka yv.

Kotak dialog yang ditampilkan di Emulator Firebase untuk memulai pengumpulan dengan ID koleksi yang berisi frasa

  1. Jika Anda berhasil menginstal ekstensi, ekstensi akan membuat kolom baru bernama hash di dokumen.

Koleksi pengguna dengan dokumen pengguna yang memiliki kolom xv, yv, dan hash.

Pembersihan untuk menghindari konflik

  • Setelah selesai menguji, uninstal ekstensi. Anda akan mengupdate kode ekstensi dan tidak ingin bentrok dengan ekstensi saat ini di kemudian hari.

Ekstensi memungkinkan beberapa versi ekstensi yang sama diinstal sekaligus, jadi dengan meng-uninstal, Anda memastikan tidak ada konflik dengan ekstensi yang diinstal sebelumnya.

firebase ext:uninstall geohash-ext

Solusi saat ini berhasil, tetapi seperti yang disebutkan di awal project, terdapat kunci API hard code untuk menyimulasikan komunikasi dengan layanan. Bagaimana Anda dapat menggunakan kunci API pengguna akhir alih-alih kunci yang awalnya diberikan? Baca terus untuk mengetahuinya.

6. Membuat pengguna ekstensi dapat dikonfigurasi

Pada tahap codelab ini, Anda memiliki ekstensi yang dikonfigurasi untuk digunakan dengan penyiapan fungsi yang tidak dapat berubah yang telah Anda tulis, tetapi bagaimana jika pengguna ingin menggunakan lintang dan bujur, bukan y dan x, untuk kolom yang menunjukkan lokasi di bidang kartesius? Selain itu, bagaimana Anda bisa membuat pengguna akhir menyediakan kunci API mereka sendiri, daripada membiarkan mereka menggunakan kunci API yang disediakan? Anda dapat melebihi kuota untuk API tersebut dengan cepat. Dalam hal ini, Anda menyiapkan dan menggunakan parameter.

Menentukan parameter dasar dalam file extension.yaml

Mulai dengan mengonversi item yang mungkin memiliki konfigurasi kustom bagi developer. Yang pertama adalah parameter XFIELD dan YFIELD.

  1. Di file extension.yaml, tambahkan kode berikut, yang menggunakan parameter kolom XFIELD dan YFIELD. Parameter ini berada di dalam properti YAML params yang ditentukan sebelumnya:

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 memberi nama parameter dengan cara yang dapat dilihat oleh Anda, sebagai produser ekstensi. Gunakan nilai ini nanti saat menentukan nilai parameter.
  • label adalah ID yang dapat dibaca manusia bagi developer untuk memberi tahu fungsi parameter.
  • description memberikan deskripsi terperinci tentang nilai. Karena mendukung markdown, API ini dapat ditautkan ke dokumentasi tambahan, atau menyoroti kata-kata yang mungkin penting bagi developer.
  • type menentukan mekanisme input terkait cara pengguna menetapkan nilai parameter. Ada banyak jenis yang ada, termasuk string, select, multiSelect, selectResource, dan secret. Untuk mempelajari setiap opsi ini lebih lanjut, lihat dokumentasi.
  • validationRegex membatasi entri developer ke nilai ekspresi reguler tertentu (dalam contoh, ini didasarkan pada panduan nama kolom sederhana yang tercantum di sini); dan jika gagal...
  • validationErrorMessage memberi tahu developer tentang nilai kegagalan.
  • default adalah nilai yang akan dihasilkan jika developer tidak memasukkan teks apa pun.
  • wajib berarti developer tidak diwajibkan memasukkan teks apa pun.
  • immutable memungkinkan developer mengupdate ekstensi ini dan mengubah nilai ini. Dalam hal ini, developer harus dapat mengubah nama kolom saat persyaratannya berubah.
  • contoh memberikan gambaran tentang tampilan input yang valid.

Sangat banyak yang saya pahami.

  1. Anda memiliki tiga parameter lagi untuk ditambahkan ke file extension.yaml sebelum menambahkan parameter khusus.
  - 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

Menentukan parameter sensitif

Sekarang, Anda perlu mengelola kunci API yang ditentukan pengguna. Ini adalah string sensitif yang tidak boleh disimpan dalam teks biasa dalam fungsi. Simpan nilai ini di Cloud secret manager. Ini adalah lokasi khusus di cloud yang menyimpan rahasia terenkripsi, dan mencegah kebocoran rahasia secara tidak sengaja. Hal ini mengharuskan developer membayar penggunaan layanan ini, tetapi hal ini menambahkan lapisan keamanan ekstra pada kunci API mereka dan berpotensi membatasi aktivitas penipuan. Dokumentasi pengguna memberi tahu developer bahwa ini adalah layanan berbayar, sehingga tidak ada kejutan dalam penagihan. Secara keseluruhan, penggunaannya mirip dengan resource string lain yang disebutkan di atas. Satu-satunya perbedaan adalah jenisnya yang disebut secret.

  • Di file extension.yaml, tambahkan kode berikut:

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

Perbarui atribut resource untuk menggunakan parameter

Seperti yang disebutkan sebelumnya, resource (bukan fungsi) menentukan cara resource diamati, sehingga resource locationUpdate perlu diupdate untuk menggunakan parameter baru.

  • Di file extension.yaml, tambahkan kode berikut:

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}

Periksa file extension.yaml

  • Tinjau file extension.yaml. Ini akan terlihat seperti berikut:

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.

Mengakses parameter dalam kode

Setelah semua parameter dikonfigurasi di file extension.yaml, tambahkan parameter tersebut ke file index.ts.

  • Di file index.ts, ganti nilai default dengan process.env.PARAMETER_NAME, yang mengambil parameter value yang sesuai dan mengisinya dalam kode fungsi yang di-deploy di project Firebase developer.

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

Biasanya, Anda ingin melakukan pemeriksaan null dengan nilai variabel lingkungan, tetapi dalam hal ini, Anda percaya bahwa nilai parameter telah disalin dengan benar. Kode kini dikonfigurasi agar berfungsi dengan parameter ekstensi.

7. Membuat dokumentasi pengguna

Sebelum menguji kode di emulator atau di marketplace ekstensi Firebase, ekstensi perlu didokumentasikan agar developer tahu apa yang mereka dapatkan saat menggunakan ekstensi.

  1. Mulai dengan membuat file PREINSTALL.md, yang digunakan untuk menjelaskan fungsi, prasyarat untuk penginstalan, dan kemungkinan implikasi penagihan.

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. Untuk menghemat waktu penulisan README.md untuk project ini, gunakan metode praktis:
firebase ext:info . --markdown > README.md

File ini menggabungkan konten file PREINSTALL.md dan detail tambahan tentang ekstensi Anda dari file extension.yaml.

Terakhir, beri tahu developer ekstensi tersebut tentang beberapa detail tambahan terkait ekstensi yang baru saja diinstal. Developer mungkin mendapatkan beberapa petunjuk dan informasi tambahan setelah menyelesaikan penginstalan dan mungkin mendapatkan beberapa tugas pasca-penginstalan mendetail seperti menyiapkan kode klien di sini.

  1. Buat file POSTINSTALL.md, lalu sertakan informasi penginstalan postingan berikut:

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

Pemantauan

Sebagai praktik terbaik, Anda dapat memantau aktivitas ekstensi yang diinstal, termasuk memeriksa respons, penggunaan, dan log-nya.

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

Perintah ini mengompilasi ulang fungsi tersebut sehingga kode sumber terbaru siap untuk di-deploy bersama ekstensi saat di-deploy ke emulator atau ke Firebase secara langsung.

Selanjutnya, buat direktori baru untuk menguji ekstensi. Karena ekstensi dikembangkan dari fungsi yang ada, jangan menguji dari folder tempat ekstensi dikonfigurasi karena ekstensi tersebut juga mencoba men-deploy fungsi dan aturan Firebase bersamanya.

Menginstal dan melakukan pengujian dengan emulator Firebase

  1. Buat direktori baru di sistem host dan hubungkan direktori tersebut ke project Firebase Anda menggunakan firebase init.
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Dari direktori tersebut, jalankan firebase ext:install untuk menginstal ekstensi. Ganti /path/to/extension dengan jalur absolut ke direktori yang berisi file extension.yaml Anda. Tindakan ini akan memulai proses penginstalan ekstensi Anda dan membuat file .env yang berisi konfigurasi Anda sebelum mengirim konfigurasi ke Firebase atau emulator.
firebase ext:install /path/to/extension
  • Karena Anda men-deploy project secara lokal, tentukan bahwa Anda ingin menggunakan file lokal, bukan Google Cloud Secret Manager.

da928c65ffa8ce15.pngS

  1. Mulai rangkaian emulator lokal:
firebase emulators:start

Menginstal dan menguji dengan project Firebase sungguhan

Anda dapat menginstal ekstensi di project Firebase yang sebenarnya. Sebaiknya gunakan project pengujian untuk pengujian. Gunakan alur kerja pengujian ini jika Anda ingin menguji alur menyeluruh ekstensi atau jika pemicu ekstensi Anda belum didukung oleh Firebase emulator suite (lihat Opsi emulator ekstensi). Saat ini emulator mendukung fungsi yang dipicu permintaan HTTP dan fungsi yang dipicu peristiwa latar belakang untuk Cloud Firestore, Realtime Database, dan Pub/Sub.

  1. Buat direktori baru di sistem host dan hubungkan direktori tersebut ke project Firebase Anda menggunakan firebase init.
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Kemudian, dari direktori tersebut, jalankan firebase ext:install untuk menginstal ekstensi. Ganti /path/to/extension dengan jalur absolut ke direktori yang berisi file extension.yaml Anda. Tindakan ini akan memulai proses penginstalan ekstensi Anda dan membuat file .env yang berisi konfigurasi Anda sebelum mengirim konfigurasi ke Firebase atau emulator.
firebase ext:install /path/to/extension
  • Karena Anda ingin langsung men-deploy ke Firebase, dan ingin menggunakan Google Cloud Secret Manager, Anda perlu mengaktifkan Secret Manager API sebelum menginstal ekstensi.
  1. Deploy ke project Firebase Anda.
firebase deploy

Menguji ekstensi

  1. Setelah menjalankan firebase deploy atau firebase emulators:start, buka tab Firestore di Firebase console atau webview emulator, yang sesuai.
  2. Tambahkan dokumen ke dalam koleksi yang ditentukan oleh kolom x dan kolom y. Dalam hal ini, dokumen yang diperbarui terletak di u/{uid} dengan kolom x dari xv dan kolom y dari yv.

Layar Emulator Firebase untuk menambahkan Data Firestore

  1. Jika Anda berhasil menginstal ekstensi, ekstensi tersebut akan membuat kolom baru bernama hash di dokumen setelah Anda menyimpan kedua kolom.

Layar database Firestore dari emulator yang menampilkan hash ditambahkan

8. Selamat!

Anda telah berhasil mengonversi Cloud Function pertama Anda menjadi ekstensi Firebase.

Anda menambahkan file extension.yaml dan mengonfigurasinya sehingga developer dapat memilih cara deployment ekstensi Anda. Kemudian, Anda membuat dokumentasi pengguna yang memberikan panduan tentang tindakan yang harus dilakukan developer ekstensi sebelum menyiapkan ekstensi dan langkah yang mungkin perlu dilakukan setelah berhasil menginstal ekstensi.

Anda kini sudah mengetahui langkah-langkah utama yang diperlukan untuk mengonversi Firebase Function menjadi Firebase Extensions yang dapat didistribusikan.

Apa selanjutnya?