Tái sử dụng mã Chức năng đám mây của bạn dưới dạng Tiện ích mở rộng Firebase

1. Trước khi bạn bắt đầu

Tiện ích mở rộng Firebase thực hiện một nhiệm vụ hoặc tập hợp nhiệm vụ cụ thể để đáp ứng các yêu cầu HTTP hoặc kích hoạt các sự kiện từ các sản phẩm Firebase và Google khác như Firebase Cloud Messaging, Cloud Firestore hoặc Pub/Sub.

Những gì bạn sẽ xây dựng

Trong lớp học lập trình này, bạn sẽ xây dựng tiện ích Firebase để băm địa lý . Sau khi được triển khai, tiện ích mở rộng của bạn sẽ chuyển đổi tọa độ X và Y thành geohash để phản hồi các sự kiện của Firestore hoặc thông qua các lệnh gọi hàm có thể gọi được. Điều này có thể được sử dụng như một giải pháp thay thế cho việc triển khai thư viện geofire trên tất cả các nền tảng mục tiêu của bạn để lưu trữ dữ liệu, giúp bạn tiết kiệm thời gian.

Tiện ích mở rộng geohash hiển thị trong bảng điều khiển Firebase

Bạn sẽ học được gì

  • Cách lấy mã Chức năng đám mây hiện có và biến nó thành Tiện ích mở rộng Firebase có thể phân phối
  • Cách thiết lập tệp extension.yaml
  • Cách lưu trữ chuỗi nhạy cảm (khóa API) trong tiện ích mở rộng
  • Cách cho phép các nhà phát triển tiện ích mở rộng định cấu hình tiện ích mở rộng cho phù hợp với nhu cầu của họ
  • Cách kiểm tra và triển khai tiện ích mở rộng

Những gì bạn cần

  • Firebase CLI (cài đặt và đăng nhập)
  • Tài khoản Google, giống như tài khoản gmail
  • Node.js và npm
  • Môi trường phát triển yêu thích của bạn

2. Thiết lập

Lấy mã

Mọi thứ bạn cần cho tiện ích mở rộng này đều có trong kho lưu trữ GitHub. Để bắt đầu, hãy lấy mã và mở nó trong môi trường phát triển yêu thích của bạn.

  1. Giải nén tệp zip đã tải xuống.
  2. Để cài đặt các phụ thuộc cần thiết, hãy mở terminal trong thư mục functions và chạy lệnh npm install .

Thiết lập căn cứ hỏa lực

Lớp học lập trình này đặc biệt khuyến khích việc sử dụng trình mô phỏng Firebase. Nếu bạn muốn thử phát triển tiện ích mở rộng bằng dự án Firebase thực, hãy xem cách tạo dự án Firebase . Lớp học lập trình này sử dụng Chức năng đám mây, vì vậy nếu đang sử dụng dự án Firebase thực thay vì trình mô phỏng, bạn cần nâng cấp lên gói giá Blaze .

Bạn muốn bỏ qua phía trước?

Bạn có thể tải xuống phiên bản hoàn chỉnh của lớp học lập trình. Nếu bạn gặp khó khăn trong quá trình thực hiện hoặc nếu bạn muốn xem một tiện ích mở rộng hoàn chỉnh trông như thế nào, hãy xem nhánh codelab-end của kho lưu trữ GitHub hoặc tải xuống tệp zip hoàn chỉnh.

3. Xem lại mã

  • Mở tệp index.ts từ tệp zip. Lưu ý rằng nó chứa hai khai báo Hàm đám mây bên trong.

Những chức năng này làm gì?

Các hàm demo này được sử dụng để băm địa lý. Họ lấy một cặp tọa độ và biến chúng thành định dạng được tối ưu hóa cho các truy vấn địa lý trong Firestore. Các hàm mô phỏng việc sử dụng lệnh gọi API để bạn có thể tìm hiểu thêm về cách xử lý các loại dữ liệu nhạy cảm trong tiện ích mở rộng. Để biết thêm thông tin, hãy xem tài liệu về cách chạy truy vấn Địa lý trên dữ liệu trong Firestore .

Hằng số hàm

Các hằng số được khai báo sớm, ở đầu tệp index.ts . Một số hằng số này được tham chiếu trong trình kích hoạt được xác định của tiện ích mở rộng.

chỉ mục.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);

Trình kích hoạt Firestore

Hàm đầu tiên trong tệp index.ts trông như thế này:

chỉ mục.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,
        }
      );
  });

Chức năng này là một trình kích hoạt Firestore . Khi một sự kiện ghi xảy ra trong cơ sở dữ liệu, hàm sẽ phản ứng với sự kiện đó bằng cách tìm kiếm trường xv và trường yv , đồng thời, nếu cả hai trường đó tồn tại, hàm sẽ tính toán geohash và ghi kết quả đầu ra vào một vị trí đầu ra tài liệu được chỉ định. Tài liệu đầu vào được xác định bởi hằng số users/{uid} , có nghĩa là hàm đọc mọi tài liệu được ghi vào users/ bộ sưu tập và sau đó xử lý một geohash cho những tài liệu đó. Sau đó, nó xuất hàm băm thành trường băm trong cùng một tài liệu.

Chức năng có thể gọi được

Hàm tiếp theo trong tệp index.ts trông như thế này:

chỉ mục.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};
});

Hãy chú ý đến hàm onCall . Nó chỉ ra rằng hàm này là một hàm có thể gọi được , có thể được gọi từ bên trong mã ứng dụng khách của bạn. Hàm có thể gọi này nhận các tham số xy và trả về một geohash. Mặc dù hàm này sẽ không được gọi trực tiếp trong lớp học lập trình này nhưng nó được đưa vào đây làm ví dụ về nội dung cần định cấu hình trong tiện ích Firebase.

4. Thiết lập file mở rộng.yaml

Bây giờ bạn đã biết mã Chức năng đám mây trong tiện ích mở rộng của mình làm gì, bạn đã sẵn sàng đóng gói để phân phối. Mỗi tiện ích mở rộng Firebase đều đi kèm với tệp extension.yaml mô tả chức năng và cách thức hoạt động của tiện ích mở rộng.

Tệp tiện ích extension.yaml yêu cầu một số siêu dữ liệu ban đầu về tiện ích mở rộng của bạn. Mỗi bước sau đây sẽ giúp bạn hiểu ý nghĩa của tất cả các trường và lý do bạn cần chúng.

  1. Tạo tệp extension.yaml trong thư mục gốc của dự án mà bạn đã tải xuống trước đó. Bắt đầu bằng cách thêm vào như sau:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

Tên của tiện ích mở rộng được sử dụng làm cơ sở cho ID phiên bản của tiện ích mở rộng (người dùng có thể cài đặt nhiều phiên bản của tiện ích mở rộng, mỗi phiên bản có ID riêng). Sau đó, Firebase tạo tên tài khoản dịch vụ của tiện ích mở rộng và tài nguyên dành riêng cho tiện ích mở rộng bằng ID phiên bản đó. Số phiên bản cho biết phiên bản tiện ích mở rộng của bạn. Nó phải tuân theo phiên bản ngữ nghĩa và bạn cần cập nhật nó bất cứ khi nào bạn thực hiện thay đổi đối với chức năng của tiện ích mở rộng. Phiên bản thông số tiện ích mở rộng được sử dụng để xác định thông số tiện ích mở rộng Firebase nào sẽ tuân theo, trong trường hợp này, v1beta được sử dụng.

  1. Thêm một số chi tiết thân thiện với người dùng vào tệp YAML:
...

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

Tên hiển thị là sự thể hiện thân thiện với tên tiện ích mở rộng của bạn khi nhà phát triển tương tác với tiện ích mở rộng của bạn. Mô tả cung cấp tổng quan ngắn gọn về chức năng của tiện ích mở rộng. Khi tiện ích mở rộng được triển khai trên Extensions.dev , nó trông giống như thế này:

Tiện ích mở rộng Geohash Converter như được thấy trong phần mở rộng.dev

  1. Chỉ định giấy phép cho mã trong tiện ích mở rộng của bạn.
...

license: Apache-2.0  # The license you want for the extension
  1. Cho biết ai đã viết tiện ích mở rộng và có cần thanh toán để cài đặt tiện ích mở rộng hay không:
...

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

billingRequired: true

Phần author được sử dụng để cho phép người dùng của bạn biết cần liên hệ với ai trong trường hợp họ gặp sự cố với tiện ích mở rộng hoặc muốn biết thêm thông tin về tiện ích mở rộng đó. billingRequired là tham số bắt buộc và phải được đặt thành true vì tất cả tiện ích mở rộng đều dựa vào Cloud Functions, yêu cầu gói Blaze.

Điều này bao gồm số lượng trường tối thiểu bắt buộc trong tệp extension.yaml để xác định tiện ích mở rộng này. Để biết thêm chi tiết về thông tin nhận dạng khác mà bạn có thể chỉ định trong tiện ích mở rộng, hãy xem tài liệu .

5. Chuyển đổi mã Chức năng đám mây thành tài nguyên Tiện ích mở rộng

Tài nguyên tiện ích mở rộng là một mục mà Firebase tạo trong dự án trong quá trình cài đặt tiện ích mở rộng. Sau đó, tiện ích mở rộng sở hữu các tài nguyên đó và có tài khoản dịch vụ cụ thể hoạt động trên chúng. Trong dự án này, các tài nguyên đó là Cloud Functions, tài nguyên này phải được xác định trong tệp extension.yaml vì tiện ích mở rộng sẽ không tự động tạo tài nguyên từ mã trong thư mục hàm. Nếu Chức năng đám mây của bạn không được khai báo rõ ràng dưới dạng tài nguyên thì chúng không thể được triển khai khi tiện ích mở rộng được triển khai.

Vị trí triển khai do người dùng xác định

  1. Cho phép người dùng chỉ định vị trí nơi họ muốn triển khai tiện ích mở rộng này và quyết định xem nên lưu trữ tiện ích mở rộng gần người dùng cuối hơn hay gần cơ sở dữ liệu của họ hơn. Trong tệp extension.yaml , hãy bao gồm tùy chọn để chọn vị trí.

phần mở rộng.yaml

Bây giờ bạn đã sẵn sàng viết cấu hình cho tài nguyên hàm.

  1. Trong tệp extension.yaml , tạo một đối tượng tài nguyên cho hàm locationUpdate . Nối phần sau vào tệp 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}

Bạn xác định name là tên hàm được xác định trong tệp index.ts của dự án. Bạn chỉ định type chức năng đang được triển khai, hiện tại, loại chức năng này phải luôn là firebaseextensions.v1beta.function . Sau đó, bạn xác định properties của hàm này. thuộc tính đầu tiên bạn xác định là eventTrigger được liên kết với hàm này. Để phản ánh những gì tiện ích mở rộng hiện hỗ trợ, bạn sử dụng eventType của providers/cloud.firestore/eventTypes/document.write , được tìm thấy trong Chức năng ghi đám mây cho tài liệu tiện ích mở rộng của bạn . Bạn xác định resource là vị trí của tài liệu. Vì mục tiêu hiện tại của bạn là phản chiếu những gì tồn tại trong mã nên đường dẫn tài liệu sẽ lắng nghe users/{uid} , với vị trí cơ sở dữ liệu mặc định trước nó.

  1. Tiện ích mở rộng cần có quyền đọc và ghi đối với cơ sở dữ liệu Firestore. Ở cuối tệp extension.yaml , hãy chỉ định vai trò IAM mà tiện ích mở rộng có quyền truy cập để hoạt động với cơ sở dữ liệu trong dự án Firebase của nhà phát triển.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Vai trò datastore.user xuất phát từ danh sách vai trò IAM được hỗ trợ cho tiện ích mở rộng . Vì tiện ích mở rộng sẽ đọc và ghi nên vai trò datastore.user rất phù hợp ở đây.

  1. Chức năng có thể gọi được cũng phải được thêm vào. Trong tệp extension.yaml , tạo một tài nguyên mới trong thuộc tính tài nguyên. Các thuộc tính này dành riêng cho một hàm có thể gọi được:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

Mặc dù tài nguyên trước đó sử dụng eventTrigger , nhưng ở đây bạn sử dụng httpsTrigger , bao gồm cả hàm có thể gọi và hàm HTTPS.

Kiểm tra mã

Cần rất nhiều cấu hình để làm cho extension.yaml của bạn khớp với mọi thứ được thực hiện bằng mã trong tệp index.ts của bạn. Tệp extension.yaml đã hoàn thành sẽ trông như thế này vào thời điểm này:

phần mở rộng.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.

Kiểm tra tình trạng

Tại thời điểm này, bạn đã thiết lập các phần chức năng ban đầu của tiện ích mở rộng, vì vậy bạn thực sự có thể dùng thử nó bằng trình mô phỏng Firebase!

  1. Nếu bạn chưa làm vậy, hãy gọi npm run build trong thư mục chức năng của dự án tiện ích mở rộng đã tải xuống.
  2. Tạo một thư mục mới trên hệ thống máy chủ của bạn và kết nối thư mục đó với dự án Firebase của bạn bằng 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. Từ cùng thư mục, chạy firebase ext:install . Thay thế /path/to/extension bằng đường dẫn tuyệt đối đến thư mục chứa tệp extension.yaml của bạn.
firebase ext:install /path/to/extension
    This command does two things:
  • Nó nhắc bạn chỉ định cấu hình cho phiên bản tiện ích mở rộng và nó tạo một tệp *.env chứa thông tin cấu hình cho phiên bản đó.
  • Nó thêm phiên bản tiện ích mở rộng vào phần extensions của firebase.json của bạn. Điều này hoạt động như một bản đồ ID phiên bản tới phiên bản tiện ích mở rộng.
  • Vì bạn đang triển khai dự án cục bộ nên bạn có thể chỉ định rằng bạn muốn sử dụng tệp cục bộ thay vì Trình quản lý bí mật của Google Cloud.

Ảnh chụp màn hình quá trình cài đặt tiện ích mở rộng cho thấy Tệp cục bộ đang được sử dụng để làm bí mật khi cài đặt tiện ích mở rộng này

  1. Khởi động trình giả lập Firebase với cấu hình mới:
firebase emulators:start
  1. Sau khi chạy emulators:start , hãy điều hướng đến tab Firestore trong chế độ xem web của trình mô phỏng.
  2. Thêm tài liệu vào bộ sưu tập users với trường số xv và trường số yv .

Hộp thoại hiển thị trong Trình mô phỏng Firebase để bắt đầu bộ sưu tập có ID bộ sưu tập chứa cụm từ

  1. Nếu bạn cài đặt thành công tiện ích mở rộng, tiện ích mở rộng sẽ tạo một trường mới gọi là hash trong tài liệu.

Bộ sưu tập người dùng với tài liệu người dùng có trường xv, yv và hash.

Dọn dẹp để tránh xung đột

  • Sau khi kiểm tra xong, hãy gỡ cài đặt tiện ích mở rộng—bạn sẽ cập nhật mã tiện ích mở rộng và không muốn xung đột với tiện ích mở rộng hiện tại sau này.

Tiện ích mở rộng cho phép cài đặt nhiều phiên bản của cùng một tiện ích mở rộng cùng một lúc, do đó, bằng cách gỡ cài đặt, bạn đảm bảo rằng không có xung đột với tiện ích mở rộng đã cài đặt trước đó.

firebase ext:uninstall geohash-ext

Giải pháp hiện tại hoạt động nhưng như đã đề cập ở phần đầu của dự án, có một khóa API được mã hóa cứng để mô phỏng giao tiếp với một dịch vụ. Làm cách nào bạn có thể sử dụng khóa API của người dùng cuối thay vì khóa API được cung cấp ban đầu? Đọc để tìm hiểu.

6. Làm cho người dùng tiện ích mở rộng có thể cấu hình được

Tại thời điểm này trong lớp học lập trình, bạn có một tiện ích mở rộng được định cấu hình để sử dụng với thiết lập theo ý kiến ​​của các hàm mà bạn đã viết, nhưng điều gì sẽ xảy ra nếu người dùng của bạn muốn sử dụng vĩ độ và kinh độ thay vì yx cho các trường biểu thị vị trí trên mặt phẳng Descartes? Ngoài ra, làm cách nào bạn có thể yêu cầu người dùng cuối cung cấp khóa API của riêng họ thay vì để họ sử dụng khóa API được cung cấp? Bạn có thể nhanh chóng vượt quá hạn ngạch cho API đó. Trong trường hợp này, bạn thiết lập và sử dụng các tham số.

Xác định các tham số cơ bản trong file extension.yaml

Bắt đầu bằng cách chuyển đổi các mục mà nhà phát triển có thể có cấu hình tùy chỉnh. Đầu tiên sẽ là tham số XFIELDYFIELD .

  1. Trong tệp extension.yaml , thêm mã sau, sử dụng tham số trường XFIELDYFIELD . Các tham số này nằm bên trong thuộc tính YAML params được xác định trước đó:

phần mở rộng.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 đặt tên tham số theo cách mà bạn, nhà sản xuất tiện ích mở rộng, có thể nhìn thấy. Sử dụng giá trị này sau này khi chỉ định các giá trị tham số.
  • nhãn là mã định danh mà con người có thể đọc được đối với nhà phát triển để cho họ biết tham số đó làm gì.
  • mô tả cung cấp một mô tả chi tiết về giá trị. Vì điều này hỗ trợ đánh dấu nên nó có thể liên kết đến tài liệu bổ sung hoặc có thể đánh dấu các từ có thể quan trọng đối với nhà phát triển.
  • type xác định cơ chế đầu vào về cách người dùng đặt giá trị tham số. Có nhiều loại tồn tại, bao gồm string , select , multiSelect , selectResourcesecret . Để tìm hiểu thêm về từng tùy chọn này, hãy xem tài liệu .
  • validationRegex ràng buộc mục nhập của nhà phát triển ở một giá trị biểu thức chính quy nhất định (trong ví dụ này, nó dựa trên các nguyên tắc tên trường đơn giản được tìm thấy ở đây ); và nếu thất bại...
  • validationErrorMessage cảnh báo cho nhà phát triển về giá trị lỗi.
  • mặc định là giá trị sẽ như thế nào nếu nhà phát triển không nhập bất kỳ văn bản nào.
  • bắt buộc có nghĩa là nhà phát triển không bắt buộc phải nhập bất kỳ văn bản nào.
  • bất biến cho phép nhà phát triển cập nhật tiện ích mở rộng này và thay đổi giá trị này. Trong trường hợp này, nhà phát triển có thể thay đổi tên trường khi yêu cầu của họ thay đổi.
  • ví dụ này cung cấp ý tưởng về đầu vào hợp lệ sẽ trông như thế nào.

Đó là rất nhiều điều để hiểu!

  1. Bạn có thêm ba tham số để thêm vào tệp extension.yaml trước khi thêm một tham số đặc biệt.
  - 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

Xác định các thông số nhạy cảm

Bây giờ, bạn cần quản lý khóa API mà người dùng chỉ định. Đây là một chuỗi nhạy cảm không được lưu trữ ở dạng văn bản thuần túy trong hàm. Thay vào đó, hãy lưu trữ giá trị này trong Trình quản lý bí mật của Đám mây . Đây là một vị trí đặc biệt trên đám mây lưu trữ các bí mật được mã hóa và ngăn chúng vô tình bị rò rỉ. Điều này yêu cầu nhà phát triển phải trả tiền cho việc sử dụng dịch vụ này nhưng nó bổ sung thêm một lớp bảo mật cho các khóa API của họ và có khả năng hạn chế hoạt động gian lận. Tài liệu dành cho người dùng cảnh báo nhà phát triển rằng đây là dịch vụ phải trả phí, do đó không có bất kỳ điều gì bất ngờ trong việc thanh toán. Nhìn chung, cách sử dụng cũng tương tự như các tài nguyên chuỗi khác được đề cập ở trên. Sự khác biệt duy nhất là loại được gọi là secret .

  • Trong tệp extension.yaml , thêm đoạn mã sau:

phần mở rộng.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

Cập nhật thuộc tính resource để sử dụng tham số

Như đã đề cập trước đó, tài nguyên (không phải hàm) xác định cách quan sát tài nguyên, do đó tài nguyên locationUpdate cần được cập nhật để sử dụng tham số mới.

  • Trong tệp extension.yaml , thêm đoạn mã sau:

phần mở rộng.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}

Kiểm tra tệp extension.yaml

  • Xem lại tệp extension.yaml . Nó sẽ trông giống như thế này:

phần mở rộng.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.

Truy cập các tham số trong mã

Bây giờ tất cả các tham số đã được định cấu hình trong tệp extension.yaml , hãy thêm chúng vào tệp index.ts .

  • Trong tệp index.ts , hãy thay thế các giá trị mặc định bằng process.env.PARAMETER_NAME để tìm nạp các giá trị tham số thích hợp và điền chúng vào mã chức năng được triển khai trên dự án Firebase của nhà phát triển.

chỉ mục.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!;

Thông thường, bạn muốn thực hiện kiểm tra null với các giá trị biến môi trường, nhưng trong trường hợp này, bạn tin tưởng rằng các giá trị tham số được sao chép chính xác. Mã hiện được cấu hình để hoạt động với các tham số mở rộng.

7. Tạo tài liệu người dùng

Trước khi thử nghiệm mã trên trình mô phỏng hoặc trên thị trường tiện ích mở rộng Firebase, tiện ích mở rộng cần phải được ghi lại để nhà phát triển biết họ sẽ nhận được gì khi sử dụng tiện ích mở rộng.

  1. Bắt đầu bằng cách tạo tệp PREINSTALL.md , tệp này được sử dụng để mô tả chức năng, mọi điều kiện tiên quyết để cài đặt và các tác động thanh toán tiềm ẩn.

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. Để tiết kiệm thời gian viết README.md cho dự án này, hãy sử dụng phương pháp tiện lợi:
firebase ext:info . --markdown > README.md

Điều này kết hợp nội dung của tệp PREINSTALL.md và các chi tiết bổ sung về tiện ích mở rộng từ tệp extension.yaml của bạn.

Cuối cùng, hãy thông báo cho nhà phát triển tiện ích mở rộng về một số chi tiết bổ sung liên quan đến tiện ích mở rộng vừa được cài đặt. Nhà phát triển có thể nhận được một số hướng dẫn và thông tin bổ sung sau khi hoàn tất quá trình cài đặt và có thể nhận được một số tác vụ chi tiết sau khi cài đặt như thiết lập mã máy khách tại đây.

  1. Tạo tệp POSTINSTALL.md , sau đó bao gồm thông tin cài đặt bài đăng sau:

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

Giám sát

Cách tốt nhất là bạn có thể giám sát hoạt động của tiện ích mở rộng đã cài đặt của mình, bao gồm kiểm tra tình trạng, mức sử dụng và nhật ký của tiện ích mở rộng đó.

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

Việc này sẽ biên dịch lại các chức năng để mã nguồn mới nhất sẵn sàng triển khai cùng với tiện ích mở rộng khi nó được triển khai trực tiếp vào trình mô phỏng hoặc tới Firebase.

Tiếp theo, tạo một thư mục mới để kiểm tra tiện ích mở rộng. Vì tiện ích mở rộng được phát triển từ các chức năng hiện có nên không kiểm tra từ thư mục chứa tiện ích mở rộng được định cấu hình vì thư mục đó cũng cố gắng triển khai các chức năng và quy tắc Firebase cùng với nó.

Cài đặt và thử nghiệm với trình giả lập Firebase

  1. Tạo một thư mục mới trên hệ thống máy chủ của bạn và kết nối thư mục đó với dự án Firebase của bạn bằng firebase init .
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Từ thư mục đó, hãy chạy firebase ext:install để cài đặt tiện ích mở rộng. Thay thế /path/to/extension bằng đường dẫn tuyệt đối đến thư mục chứa tệp extension.yaml của bạn. Thao tác này sẽ bắt đầu quá trình cài đặt tiện ích mở rộng của bạn và tạo tệp .env chứa cấu hình của bạn trước khi đẩy cấu hình sang Firebase hoặc trình mô phỏng.
firebase ext:install /path/to/extension
  • Vì bạn đang triển khai dự án cục bộ, hãy chỉ định rằng bạn muốn sử dụng tệp cục bộ thay vì Trình quản lý bí mật của Google Cloud.

da928c65ffa8ce15.png

  1. Bắt đầu bộ mô phỏng cục bộ:
firebase emulators:start

Cài đặt và thử nghiệm với dự án Firebase thực sự

Bạn có thể cài đặt tiện ích mở rộng của mình trong dự án Firebase thực tế. Bạn nên sử dụng một dự án thử nghiệm để thử nghiệm. Sử dụng quy trình kiểm tra này nếu bạn muốn kiểm tra luồng từ đầu đến cuối của tiện ích mở rộng hoặc nếu trình kích hoạt tiện ích mở rộng của bạn chưa được bộ mô phỏng Firebase hỗ trợ (xem tùy chọn Trình mô phỏng tiện ích mở rộng ). Trình mô phỏng hiện hỗ trợ các hàm kích hoạt yêu cầu HTTP và các hàm kích hoạt sự kiện nền cho Cloud Firestore, Cơ sở dữ liệu thời gian thực và Pub/Sub.

  1. Tạo một thư mục mới trên hệ thống máy chủ của bạn và kết nối thư mục đó với dự án Firebase của bạn bằng firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Sau đó, từ thư mục đó, hãy chạy firebase ext:install để cài đặt tiện ích mở rộng. Thay thế /path/to/extension bằng đường dẫn tuyệt đối đến thư mục chứa tệp extension.yaml của bạn. Thao tác này sẽ bắt đầu quá trình cài đặt tiện ích mở rộng của bạn và tạo tệp .env chứa cấu hình của bạn trước khi đẩy cấu hình sang Firebase hoặc trình mô phỏng.
firebase ext:install /path/to/extension
  • Vì bạn muốn triển khai trực tiếp lên Firebase và muốn sử dụng Google Cloud Secret Manager, bạn cần kích hoạt API Secret Manager trước khi cài đặt tiện ích mở rộng.
  1. Triển khai vào dự án Firebase của bạn.
firebase deploy

Kiểm tra phần mở rộng

  1. Sau khi chạy firebase deploy hoặc firebase emulators:start , hãy điều hướng đến tab Firestore của bảng điều khiển Firebase hoặc chế độ xem web của trình mô phỏng, nếu thích hợp.
  2. Thêm tài liệu vào bộ sưu tập được chỉ định bởi trường x và trường y . Trong trường hợp này, các tài liệu cập nhật được đặt tại u/{uid} với trường xxv và trường yyv .

Màn hình Trình mô phỏng Firebase để thêm Bản ghi Firestore

  1. Nếu bạn cài đặt thành công tiện ích mở rộng, tiện ích mở rộng sẽ tạo một trường mới gọi là hash trong tài liệu sau khi bạn lưu hai trường.

Màn hình cơ sở dữ liệu Firestore từ trình mô phỏng hiển thị hàm băm được thêm vào

8. Xin chúc mừng!

Bạn đã chuyển đổi thành công Chức năng đám mây đầu tiên của mình thành Tiện ích mở rộng Firebase!

Bạn đã thêm tệp extension.yaml và định cấu hình tệp đó để các nhà phát triển có thể chọn cách họ muốn triển khai tiện ích mở rộng của bạn. Sau đó, bạn đã tạo tài liệu dành cho người dùng cung cấp hướng dẫn về những gì nhà phát triển tiện ích mở rộng nên làm trước khi thiết lập tiện ích mở rộng và những bước họ có thể cần thực hiện sau khi cài đặt thành công tiện ích mở rộng.

Bây giờ bạn đã biết các bước chính cần thiết để chuyển đổi Hàm Firebase thành Tiện ích mở rộng Firebase có thể phân phối.

Cái gì tiếp theo?