นำโค้ด Cloud Functions ของคุณไปใช้ใหม่เป็นส่วนขยายของ Firebase

1. ก่อนที่คุณจะเริ่ม

ส่วนขยาย Firebase ทำงานเฉพาะหรือชุดงานเพื่อตอบสนองต่อคำขอ HTTP หรือทริกเกอร์เหตุการณ์จาก Firebase และผลิตภัณฑ์อื่นๆ ของ Google เช่น Firebase Cloud Messaging, Cloud Firestore หรือ Pub/Sub

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะสร้างส่วนขยาย Firebase สำหรับ geohashing เมื่อปรับใช้แล้ว ส่วนขยายของคุณจะแปลงพิกัด X และ Y เป็น Geohash เพื่อตอบสนองต่อเหตุการณ์ Firestore หรือผ่านการเรียกใช้ฟังก์ชันที่เรียกใช้ได้ ซึ่งสามารถใช้เป็นอีกทางเลือกหนึ่งใน การนำไลบรารี geofire ไปใช้ ในทุกแพลตฟอร์มเป้าหมายของคุณสำหรับการจัดเก็บข้อมูล ซึ่งจะช่วยประหยัดเวลา

ส่วนขยาย geohash ที่แสดงในคอนโซล Firebase

สิ่งที่คุณจะได้เรียนรู้

  • วิธีนำโค้ด Cloud Functions ที่มีอยู่มาแปลงเป็น Firebase Extension ที่แจกจ่ายได้
  • วิธีการตั้งค่าไฟล์ extension.yaml
  • วิธีจัดเก็บสตริงที่ละเอียดอ่อน (คีย์ API) ในส่วนขยาย
  • วิธีอนุญาตให้นักพัฒนาส่วนขยายกำหนดค่าให้เหมาะกับความต้องการของพวกเขา
  • วิธีทดสอบและปรับใช้ส่วนขยาย

สิ่งที่คุณต้องการ

  • Firebase CLI (ติดตั้งและเข้าสู่ระบบ)
  • บัญชี Google เช่น บัญชี Gmail
  • Node.js และ npm
  • สภาพแวดล้อมการพัฒนาที่คุณชื่นชอบ

2. ตั้งค่า

รับรหัส

ทุกสิ่งที่คุณต้องการสำหรับส่วนขยายนี้อยู่ใน repo GitHub ในการเริ่มต้น ให้คว้าโค้ดและเปิดมันในสภาพแวดล้อมการพัฒนาที่คุณชื่นชอบ

  1. แตกไฟล์ zip ที่ดาวน์โหลดมา
  2. หากต้องการติดตั้งการขึ้นต่อกันที่จำเป็น ให้เปิดเทอร์มินัลใน functions ฟังก์ชั่นแล้วรันคำสั่ง npm install

ตั้งค่า Firebase

Codelab นี้สนับสนุนการใช้โปรแกรมจำลอง Firebase เป็นอย่างยิ่ง หากคุณต้องการทดลองใช้การพัฒนาส่วนขยายด้วยโปรเจ็กต์ Firebase จริง โปรดดู สร้างโปรเจ็กต์ Firebase Codelab นี้ใช้ฟังก์ชันคลาวด์ ดังนั้นหากคุณใช้โปรเจ็กต์ Firebase จริงแทนโปรแกรมจำลอง คุณจะต้อง อัปเกรดเป็นแผนการกำหนดราคา Blaze

ต้องการที่จะข้ามไปข้างหน้า?

คุณสามารถดาวน์โหลด Codelab เวอร์ชันสมบูรณ์ได้ หากคุณติดขัดระหว่างการทำงานหรือถ้าคุณต้องการดูว่าส่วนขยายที่เสร็จสมบูรณ์แล้วเป็นอย่างไร ให้ตรวจสอบสาขา codelab-end ของ พื้นที่เก็บข้อมูล GitHub หรือดาวน์โหลดไฟล์ zip ที่เสร็จสมบูรณ์

3. ตรวจสอบโค้ด

  • เปิดไฟล์ index.ts จากไฟล์ zip โปรดสังเกตว่ามีการประกาศ Cloud Functions สองรายการอยู่ภายใน

ฟังก์ชั่นเหล่านี้มีไว้ทำอะไร?

ฟังก์ชันสาธิตเหล่านี้ใช้สำหรับ geohashing พวกเขาใช้คู่พิกัดและแปลงเป็นรูปแบบที่ปรับให้เหมาะสมสำหรับการสืบค้นทางภูมิศาสตร์ใน Firestore ฟังก์ชันนี้จะจำลองการใช้การเรียก API เพื่อให้คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการจัดการประเภทข้อมูลที่ละเอียดอ่อนในส่วนขยาย สำหรับข้อมูลเพิ่มเติม โปรดดูเอกสารประกอบเกี่ยวกับ การเรียกใช้คำสั่ง Geo กับข้อมูลใน Firestore

ค่าคงที่ของฟังก์ชัน

ค่าคงที่จะถูกประกาศตั้งแต่เนิ่นๆ ที่ด้านบนของไฟล์ index.ts ค่าคงที่เหล่านี้บางส่วนมีการอ้างอิงในทริกเกอร์ที่กำหนดของส่วนขยาย

ดัชนี.ts

import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";

const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

initializeApp();

const service = new GeoHashService(apiKey);

ทริกเกอร์ Firestore

ฟังก์ชันแรกในไฟล์ index.ts มีลักษณะดังนี้:

ดัชนี.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,
        }
      );
  });

ฟังก์ชันนี้เป็น ทริกเกอร์ Firestore เมื่อมีเหตุการณ์การเขียนเกิดขึ้นในฐานข้อมูล ฟังก์ชันจะตอบสนองต่อเหตุการณ์นั้นโดยการค้นหาฟิลด์ xv และฟิลด์ yv และหากมีทั้งสองฟิลด์ดังกล่าว ฟังก์ชันจะคำนวณ geohash และเขียนเอาต์พุตไปยังตำแหน่งเอาต์พุตเอกสารที่ระบุ เอกสารอินพุตถูกกำหนดโดยค่าคงที่ users/{uid} ซึ่งหมายความว่าฟังก์ชันจะอ่านเอกสารทุกฉบับที่เขียนถึง users/ คอลเลกชัน จากนั้นจึงประมวลผล geohash สำหรับเอกสารเหล่านั้น จากนั้นจะส่งออกแฮชไปยังช่องแฮชในเอกสารเดียวกัน

ฟังก์ชั่นที่สามารถเรียกได้

ฟังก์ชั่นถัดไปในไฟล์ index.ts มีลักษณะดังนี้:

ดัชนี.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};
});

สังเกตฟังก์ชัน onCall บ่งชี้ว่าฟังก์ชันนี้เป็น ฟังก์ชันที่สามารถเรียกได้ ซึ่งสามารถเรียกได้จากภายในโค้ดแอปพลิเคชันไคลเอ็นต์ของคุณ ฟังก์ชันที่สามารถเรียกได้นี้รับพารามิเตอร์ x และ y และส่งคืน geohash แม้ว่าฟังก์ชันนี้จะไม่ถูกเรียกใช้โดยตรงใน Codelab นี้ แต่ฟังก์ชันนี้ก็รวมไว้ที่นี่เป็นตัวอย่างของสิ่งที่ต้องกำหนดค่าในส่วนขยาย Firebase

4. ตั้งค่าไฟล์ extension.yaml

เมื่อคุณทราบแล้วว่าโค้ด Cloud Functions ในส่วนขยายของคุณทำหน้าที่อะไร คุณก็พร้อมที่จะจัดแพ็คเกจเพื่อเผยแพร่แล้ว ส่วนขยาย Firebase ทุกไฟล์มาพร้อมกับไฟล์ extension.yaml ที่อธิบายว่าส่วนขยายนั้นทำอะไรและทำงานอย่างไร

ไฟล์ extension.yaml ต้องมีข้อมูลเมตาเริ่มต้นเกี่ยวกับส่วนขยายของคุณ แต่ละขั้นตอนต่อไปนี้จะช่วยให้คุณเข้าใจว่าฟิลด์ทั้งหมดหมายถึงอะไร และเหตุใดคุณจึงต้องการฟิลด์เหล่านั้น

  1. สร้างไฟล์ extension.yaml ในไดเรกทอรีรากของโปรเจ็กต์ที่คุณดาวน์โหลดไว้ก่อนหน้านี้ เริ่มต้นด้วยการเพิ่มสิ่งต่อไปนี้:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

ชื่อของส่วนขยายจะใช้เป็นฐานของ ID อินสแตนซ์ของส่วนขยาย (ผู้ใช้สามารถติดตั้งส่วนขยายได้หลายอินสแตนซ์ โดยแต่ละรายการมี ID ของตัวเอง) จากนั้น Firebase จะสร้างชื่อบัญชีบริการของส่วนขยายและทรัพยากรเฉพาะส่วนขยายโดยใช้รหัสอินสแตนซ์นั้น หมายเลขเวอร์ชันระบุเวอร์ชันของส่วนขยายของคุณ ต้องเป็นไปตาม การกำหนดเวอร์ชันเชิงความหมาย และคุณต้องอัปเดตทุกครั้งที่คุณทำการเปลี่ยนแปลงฟังก์ชันการทำงานของส่วนขยาย เวอร์ชันข้อกำหนดส่วนขยายใช้เพื่อกำหนดข้อกำหนดส่วนขยาย Firebase ที่จะปฏิบัติตาม ในกรณีนี้ จะใช้ v1beta

  1. เพิ่มรายละเอียดที่เป็นมิตรต่อผู้ใช้ลงในไฟล์ YAML:
...

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

ชื่อที่แสดงคือการแสดงชื่อส่วนขยายของคุณอย่างเป็นมิตรเมื่อนักพัฒนาโต้ตอบกับส่วนขยายของคุณ คำอธิบายจะให้ภาพรวมคร่าวๆ ว่าส่วนขยายทำอะไรได้บ้าง เมื่อส่วนขยายถูกปรับใช้บน extensions.dev จะมีลักษณะดังนี้:

ส่วนขยาย Geohash Converter ดังที่เห็นใน extensions.dev

  1. ระบุใบอนุญาตสำหรับรหัสในส่วนขยายของคุณ
...

license: Apache-2.0  # The license you want for the extension
  1. ระบุว่าใครเป็นผู้เขียนส่วนขยายและจำเป็นต้องเรียกเก็บเงินเพื่อติดตั้งหรือไม่:
...

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

billingRequired: true

ส่วน author ใช้เพื่อแจ้งให้ผู้ใช้ของคุณทราบว่าควรติดต่อใครในกรณีที่พวกเขามีปัญหากับส่วนขยายหรือต้องการข้อมูลเพิ่มเติมเกี่ยวกับส่วนขยาย billingRequired เป็นพารามิเตอร์ที่จำเป็นและต้องตั้งค่าเป็น true เนื่องจากส่วนขยายทั้งหมดอาศัย Cloud Functions ซึ่งต้องใช้แผน Blaze

ซึ่งครอบคลุมจำนวนฟิลด์ขั้นต่ำที่จำเป็นในไฟล์ extension.yaml เพื่อระบุส่วนขยายนี้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับข้อมูลการระบุอื่นๆ ที่คุณสามารถระบุในส่วนขยาย โปรดดู เอกสารประกอบ

5. แปลงโค้ด Cloud Functions เป็นทรัพยากรส่วนขยาย

ทรัพยากรส่วนขยายคือรายการที่ Firebase สร้างในโปรเจ็กต์ระหว่างการติดตั้งส่วนขยาย ส่วนขยายจะเป็นเจ้าของทรัพยากรเหล่านั้นและมีบัญชีบริการเฉพาะที่ดำเนินการกับทรัพยากรเหล่านั้น ในโปรเจ็กต์นี้ ทรัพยากรเหล่านั้นคือ Cloud Functions ซึ่งต้องกำหนดไว้ในไฟล์ extension.yaml เนื่องจากส่วนขยายจะไม่สร้างทรัพยากรจากโค้ดในโฟลเดอร์ Functions โดยอัตโนมัติ หาก Cloud Functions ของคุณไม่ได้รับการประกาศอย่างชัดเจนว่าเป็นทรัพยากร ก็จะใช้งานไม่ได้เมื่อมีการปรับใช้ส่วนขยาย

ตำแหน่งการปรับใช้ที่ผู้ใช้กำหนด

  1. อนุญาตให้ผู้ใช้สามารถระบุตำแหน่งที่ต้องการปรับใช้ส่วนขยายนี้ และตัดสินใจว่าจะเป็นการดีกว่าถ้าจะโฮสต์ส่วนขยายใกล้กับผู้ใช้ปลายทางหรือใกล้กับฐานข้อมูลมากขึ้น ในไฟล์ extension.yaml ให้ใส่ตัวเลือกในการเลือกตำแหน่ง

extension.yaml

ตอนนี้คุณพร้อมที่จะเขียนการกำหนดค่าสำหรับทรัพยากรฟังก์ชันแล้ว

  1. ในไฟล์ extension.yaml ให้สร้างออบเจ็กต์ทรัพยากรสำหรับฟังก์ชัน locationUpdate ผนวกต่อไปนี้เข้ากับไฟล์ 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}

คุณกำหนด name เป็นชื่อฟังก์ชันที่กำหนดไว้ในไฟล์ index.ts ของโครงการ คุณระบุ type ของฟังก์ชันที่กำลังปรับใช้ ซึ่งควรเป็น firebaseextensions.v1beta.function เสมอสำหรับตอนนี้ จากนั้น คุณกำหนด properties ของฟังก์ชันนี้ คุณสมบัติแรกที่คุณกำหนดคือ eventTrigger ที่เชื่อมโยงกับฟังก์ชันนี้ หากต้องการจำลองสิ่งที่ส่วนขยายรองรับในปัจจุบัน คุณใช้ eventType ของ providers/cloud.firestore/eventTypes/document.write ซึ่งพบได้ใน Write Cloud Functions สำหรับเอกสารประกอบส่วนขยายของคุณ คุณกำหนด resource เป็นตำแหน่งของเอกสาร เนื่องจากเป้าหมายปัจจุบันของคุณคือการสะท้อนสิ่งที่มีอยู่ในโค้ด เส้นทางเอกสารจะรับฟัง users/{uid} โดยมีตำแหน่งฐานข้อมูลเริ่มต้นอยู่ข้างหน้า

  1. ส่วนขยายต้องการสิทธิ์ในการอ่านและเขียนสำหรับฐานข้อมูล Firestore ที่ส่วนท้ายสุดของไฟล์ extension.yaml ให้ระบุบทบาท IAM ที่ส่วนขยายควรมีสิทธิ์เข้าถึงเพื่อทำงานกับฐานข้อมูลในโปรเจ็กต์ Firebase ของนักพัฒนา
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

บทบาท datastore.user มาจากรายการ บทบาท IAM ที่รองรับสำหรับส่วนขยาย เนื่องจากส่วนขยายจะเป็นการอ่านและการเขียน บทบาทของ datastore.user จึงเหมาะสมที่นี่

  1. ต้องเพิ่มฟังก์ชันที่เรียกได้ด้วยเช่นกัน ในไฟล์ extension.yaml ให้สร้างทรัพยากรใหม่ภายใต้คุณสมบัติทรัพยากร คุณสมบัติเหล่านี้มีความเฉพาะเจาะจงสำหรับฟังก์ชันที่สามารถเรียกได้:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

แม้ว่าทรัพยากรก่อนหน้านี้จะใช้ eventTrigger แต่ที่นี่ คุณจะใช้ httpsTrigger ซึ่งครอบคลุมทั้งฟังก์ชันที่เรียกได้และฟังก์ชัน HTTPS

ตรวจสอบรหัส

นั่นเป็นการกำหนดค่าจำนวนมากเพื่อให้ extension.yaml ของคุณตรงกับทุกสิ่งที่ทำโดยโค้ดในไฟล์ index.ts ของคุณ ไฟล์ extension.yaml ที่เสร็จสมบูรณ์ควรมีลักษณะดังนี้:

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.

การตรวจสอบสถานะ

ณ จุดนี้ คุณได้ตั้งค่าส่วนการทำงานเบื้องต้นของส่วนขยายแล้ว ดังนั้นคุณจึงสามารถทดลองใช้งานโดยใช้โปรแกรมจำลอง Firebase ได้!

  1. หากคุณยังไม่ได้ดำเนินการ ให้เรียก npm run build ในโฟลเดอร์ฟังก์ชั่นของโปรเจ็กต์ส่วนขยายที่ดาวน์โหลด
  2. สร้างไดเร็กทอรีใหม่บนระบบโฮสต์ของคุณและเชื่อมต่อไดเร็กทอรีนั้นกับโปรเจ็กต์ Firebase ของคุณโดยใช้ 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. จากไดเรกทอรีเดียวกัน ให้เรียกใช้ firebase ext:install แทนที่ /path/to/extension ด้วยพาธสัมบูรณ์ไปยังไดเร็กทอรีที่มีไฟล์ extension.yaml ของคุณ
firebase ext:install /path/to/extension
    This command does two things:
  • โดยจะแจ้งให้คุณระบุการกำหนดค่าสำหรับอินสแตนซ์ส่วนขยาย และสร้างไฟล์ *.env ที่มีข้อมูลการกำหนดค่าสำหรับอินสแตนซ์
  • โดยจะเพิ่มอินสแตนซ์ส่วนขยายไปยังส่วนส่วน extensions ของ firebase.json ของคุณ ซึ่งทำหน้าที่เป็นแผนที่ของรหัสอินสแตนซ์ไปยังเวอร์ชันส่วนขยาย
  • เนื่องจากคุณกำลังปรับใช้โปรเจ็กต์ในเครื่อง คุณจึงระบุได้ว่าต้องการใช้ไฟล์ในเครื่องแทน Google Cloud Secret Manager

ภาพหน้าจอของกระบวนการติดตั้งส่วนขยายแสดงว่าไฟล์ในเครื่องถูกใช้เป็นความลับเมื่อติดตั้งส่วนขยายนี้

  1. เริ่มโปรแกรมจำลอง Firebase ด้วยการกำหนดค่าใหม่:
firebase emulators:start
  1. หลังจากรัน emulators:start ให้ไปที่แท็บ Firestore ใน webview ของ emulators
  2. เพิ่มเอกสารลงในคอลเลกชัน users ด้วยฟิลด์หมายเลข xv และฟิลด์หมายเลข yv

กล่องโต้ตอบที่แสดงใน Firebase Emulators เพื่อเริ่มคอลเลกชันด้วยรหัสคอลเลกชันที่มีวลีนั้น

  1. หากคุณติดตั้งส่วนขยายได้สำเร็จ ส่วนขยายจะสร้างฟิลด์ใหม่ที่เรียกว่า hash ในเอกสาร

คอลเล็กชันผู้ใช้ที่มีเอกสารผู้ใช้ที่มีฟิลด์ xv, yv และ hash

ทำความสะอาดเพื่อหลีกเลี่ยงความขัดแย้ง

  • เมื่อคุณทดสอบเสร็จแล้ว ให้ถอนการติดตั้งส่วนขยาย คุณจะต้องอัปเดตโค้ดส่วนขยายและไม่ต้องการขัดแย้งกับส่วนขยายปัจจุบันในภายหลัง

ส่วนขยายอนุญาตให้ติดตั้งส่วนขยายเดียวกันได้หลายเวอร์ชันพร้อมกัน ดังนั้นการถอนการติดตั้งจะทำให้คุณมั่นใจได้ว่าไม่มีข้อขัดแย้งกับส่วนขยายที่ติดตั้งไว้ก่อนหน้านี้

firebase ext:uninstall geohash-ext

โซลูชันปัจจุบันใช้งานได้ แต่ตามที่กล่าวไว้ในตอนต้นของโปรเจ็กต์ มีคีย์ API แบบฮาร์ดโค้ดเพื่อจำลองการสื่อสารกับบริการ คุณจะใช้คีย์ API ของผู้ใช้ปลายทางแทนคีย์ที่ให้มาแต่แรกได้อย่างไร การอ่านเพื่อหา.

6. ทำให้ผู้ใช้สามารถกำหนดค่าส่วนขยายได้

ณ จุดนี้ใน Codelab คุณมีส่วนขยายที่ได้รับการกำหนดค่าเพื่อใช้กับการตั้งค่าฟังก์ชันที่คุณเขียนไว้แล้ว แต่จะเกิดอะไรขึ้นหากผู้ใช้ของคุณต้องการใช้ละติจูดและลองจิจูดแทน y และ x สำหรับฟิลด์ที่ระบุ ตำแหน่งบนเครื่องบินคาร์ทีเซียน? นอกจากนี้ คุณจะให้ผู้ใช้ระบุคีย์ API ของตนเองแทนที่จะปล่อยให้พวกเขาใช้คีย์ API ที่ให้มาได้อย่างไร คุณสามารถใช้งานโควต้าของ API นั้นเกินโควต้าได้อย่างรวดเร็ว ในกรณีนี้ คุณตั้งค่าและใช้พารามิเตอร์

กำหนดพารามิเตอร์พื้นฐานใน ไฟล์ extension.yaml

เริ่มต้นด้วยการแปลงรายการที่นักพัฒนาอาจมีการกำหนดค่าแบบกำหนดเอง ตัวแรกจะเป็นพารามิเตอร์ XFIELD และ YFIELD

  1. ในไฟล์ extension.yaml ให้เพิ่มโค้ดต่อไปนี้ ซึ่งใช้พารามิเตอร์ฟิลด์ XFIELD และ YFIELD พารามิเตอร์เหล่านี้อยู่ภายในคุณสมบัติ YAML ของ params ที่กำหนดไว้ก่อนหน้านี้:

extension.yaml

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If no value is specified, the extension searches for
      field 'xv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      value. If no value is specified, the extension searches for
      field 'yv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  • param ตั้งชื่อพารามิเตอร์ในลักษณะที่คุณซึ่งเป็นผู้สร้างส่วนขยายมองเห็นได้ ใช้ค่านี้ในภายหลังเมื่อระบุค่าพารามิเตอร์
  • label เป็นตัวระบุที่มนุษย์สามารถอ่านได้สำหรับนักพัฒนา เพื่อให้พวกเขาทราบว่าพารามิเตอร์ทำอะไร
  • description ให้คำอธิบายโดยละเอียดของค่า เนื่องจากสิ่งนี้รองรับมาร์กดาวน์ จึงสามารถลิงก์ไปยังเอกสารประกอบเพิ่มเติม หรือสามารถเน้นคำที่อาจสำคัญสำหรับนักพัฒนาได้
  • type กำหนดกลไกการป้อนข้อมูลว่าผู้ใช้จะตั้งค่าพารามิเตอร์อย่างไร มีหลายประเภทที่มีอยู่ รวมถึง string , select , multiSelect , selectResource และ secret หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับตัวเลือกแต่ละรายการ โปรดดู เอกสารประกอบ
  • validationRegex จำกัดรายการของนักพัฒนาให้มีค่า regex ที่แน่นอน (ในตัวอย่างเป็นไปตามหลักเกณฑ์ชื่อฟิลด์แบบง่าย ที่พบ ที่นี่ ) และถ้ามันล้มเหลว...
  • validationErrorMessage แจ้งเตือนผู้พัฒนาถึงค่าความล้มเหลว
  • ค่า เริ่มต้น คือค่าที่จะเป็นหากนักพัฒนาไม่ได้ป้อนข้อความใดๆ
  • จำเป็น หมายความว่านักพัฒนาไม่จำเป็นต้องป้อนข้อความใด ๆ
  • ไม่เปลี่ยนรูป ช่วยให้นักพัฒนาสามารถอัปเดตส่วนขยายนี้และเปลี่ยนแปลงค่านี้ได้ ในกรณีนี้ นักพัฒนาควรสามารถเปลี่ยนชื่อฟิลด์ได้ตามความต้องการที่เปลี่ยนไป
  • ตัวอย่าง ให้แนวคิดว่าอินพุตที่ถูกต้องอาจมีหน้าตาเป็นอย่างไร

นั่นเป็นเรื่องที่ต้องเข้าใจมาก!

  1. คุณมีพารามิเตอร์อีกสามตัวที่จะเพิ่มลงในไฟล์ extension.yaml ก่อนที่จะเพิ่มพารามิเตอร์พิเศษ
  - 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

กำหนดพารามิเตอร์ที่ละเอียดอ่อน

ตอนนี้ คุณต้องจัดการคีย์ API ที่ผู้ใช้ระบุ นี่เป็นสตริงที่ละเอียดอ่อนซึ่งไม่ควรจัดเก็บไว้ในข้อความธรรมดาในฟังก์ชัน ให้เก็บค่านี้ไว้ใน Cloud Secret Manager แทน นี่คือตำแหน่งพิเศษในระบบคลาวด์ที่เก็บความลับที่เข้ารหัส และป้องกันไม่ให้รั่วไหลโดยไม่ได้ตั้งใจ สิ่งนี้กำหนดให้นักพัฒนาต้องชำระเงินสำหรับการใช้บริการนี้ แต่จะเพิ่มการรักษาความปลอดภัยอีกชั้นเหนือคีย์ API และอาจจำกัดกิจกรรมการฉ้อโกง เอกสารสำหรับผู้ใช้จะแจ้งเตือนผู้พัฒนาว่าเป็นบริการแบบชำระเงิน เพื่อไม่ให้เกิดความประหลาดใจในการเรียกเก็บเงิน โดยรวมแล้ว การใช้งานจะคล้ายกับทรัพยากรสตริงอื่นๆ ที่กล่าวถึงข้างต้น ข้อแตกต่างเพียงอย่างเดียวคือประเภทที่เรียกว่า secret

  • ในไฟล์ extension.yaml ให้เพิ่มโค้ดต่อไปนี้:

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

อัปเดตแอตทริบิวต์ resource เพื่อใช้พารามิเตอร์

ตามที่กล่าวไว้ก่อนหน้านี้ ทรัพยากร (ไม่ใช่ฟังก์ชัน) จะกำหนดวิธีการสังเกตทรัพยากร ดังนั้นทรัพยากร locationUpdate จำเป็นต้องได้รับการอัปเดตเพื่อใช้พารามิเตอร์ใหม่

  • ในไฟล์ extension.yaml ให้เพิ่มโค้ดต่อไปนี้:

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}

ตรวจสอบ ไฟล์ extension.yaml

  • ตรวจสอบไฟล์ extension.yaml มันควรมีลักษณะดังนี้:

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.

เข้าถึงพารามิเตอร์ในโค้ด

ตอนนี้พารามิเตอร์ทั้งหมดได้รับการกำหนดค่าในไฟล์ extension.yaml แล้ว ให้เพิ่มพารามิเตอร์เหล่านั้นลงในไฟล์ index.ts

  • ในไฟล์ index.ts ให้แทนที่ค่าเริ่มต้นด้วย process.env.PARAMETER_NAME ซึ่งจะดึงค่าพารามิเตอร์ที่เหมาะสมและเติมลงในโค้ดฟังก์ชันที่ใช้งานบนโปรเจ็กต์ Firebase ของนักพัฒนา

ดัชนี.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!;

โดยปกติ คุณต้องการดำเนินการตรวจสอบค่าว่างกับค่าตัวแปรสภาพแวดล้อม แต่ในกรณีนี้ คุณเชื่อว่าค่าพารามิเตอร์จะถูกคัดลอกอย่างถูกต้อง ขณะนี้โค้ดได้รับการกำหนดค่าให้ทำงานกับพารามิเตอร์ส่วนขยายแล้ว

7. สร้างเอกสารผู้ใช้

ก่อนที่จะทดสอบโค้ดบนโปรแกรมจำลองหรือในตลาดส่วนขยาย Firebase ส่วนขยายดังกล่าวจะต้องได้รับการบันทึกไว้เพื่อให้นักพัฒนาทราบว่าตนเองจะได้รับอะไรเมื่อใช้ส่วนขยายดังกล่าว

  1. เริ่มต้นด้วยการสร้างไฟล์ PREINSTALL.md ซึ่งใช้เพื่ออธิบายฟังก์ชันการทำงาน ข้อกำหนดเบื้องต้นสำหรับการติดตั้ง และผลกระทบต่อการเรียกเก็บเงินที่อาจเกิดขึ้น

ติดตั้งล่วงหน้า.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. เพื่อประหยัดเวลาในการเขียน README.md สำหรับโปรเจ็กต์นี้ ให้ใช้วิธีการที่สะดวก:
firebase ext:info . --markdown > README.md

ซึ่งจะรวมเนื้อหาของไฟล์ PREINSTALL.md และรายละเอียดเพิ่มเติมเกี่ยวกับส่วนขยายของคุณจากไฟล์ extension.yaml

สุดท้ายนี้ แจ้งผู้พัฒนาส่วนขยายเกี่ยวกับรายละเอียดเพิ่มเติมเกี่ยวกับส่วนขยายที่เพิ่งติดตั้ง นักพัฒนาอาจได้รับคำแนะนำและข้อมูลเพิ่มเติมหลังจากการติดตั้งเสร็จสิ้น และอาจได้รับงานหลังการติดตั้งโดยละเอียด เช่น การตั้งค่ารหัสไคลเอ็นต์ที่นี่

  1. สร้างแฟ้ม POSTINSTALL.md และรวมข้อมูลการติดตั้งหลังการติดตั้งต่อไปนี้:

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

การตรวจสอบ

ตามแนวทางปฏิบัติที่ดีที่สุด คุณสามารถ ตรวจสอบกิจกรรม ของส่วนขยายที่ติดตั้งได้ รวมถึงการตรวจสอบความสมบูรณ์ การใช้งาน และบันทึกของส่วนขยายนั้น

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

ซึ่งจะคอมไพล์ฟังก์ชันใหม่เพื่อให้ซอร์สโค้ดล่าสุดพร้อมสำหรับการใช้งานควบคู่ไปกับส่วนขยายเมื่อนำไปใช้กับโปรแกรมจำลองหรือ Firebase โดยตรง

จากนั้นสร้างไดเร็กทอรีใหม่เพื่อทดสอบส่วนขยาย เนื่องจากส่วนขยายได้รับการพัฒนาจากฟังก์ชันที่มีอยู่ อย่าทดสอบจากโฟลเดอร์ที่มีการกำหนดค่าส่วนขยายไว้ เนื่องจากเป็นความพยายามในการปรับใช้ฟังก์ชันและกฎ Firebase ควบคู่ไปกับส่วนขยายด้วย

ติดตั้งและทดสอบด้วยโปรแกรมจำลอง Firebase

  1. สร้างไดเร็กทอรีใหม่บนระบบโฮสต์ของคุณและเชื่อมต่อไดเร็กทอรีนั้นกับโปรเจ็กต์ Firebase ของคุณโดยใช้ firebase init
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. จากไดเร็กทอรีนั้น ให้รัน firebase ext:install เพื่อติดตั้งส่วนขยาย แทนที่ /path/to/extension ด้วยพาธสัมบูรณ์ไปยังไดเร็กทอรีที่มีไฟล์ extension.yaml ของคุณ การดำเนินการนี้จะเริ่มกระบวนการติดตั้งสำหรับส่วนขยายของคุณและสร้างไฟล์ .env ที่มีการกำหนดค่าของคุณก่อนที่จะพุชการกำหนดค่าไปที่ Firebase หรือไปยังโปรแกรมจำลอง
firebase ext:install /path/to/extension
  • เนื่องจากคุณกำลังปรับใช้โปรเจ็กต์ในเครื่อง โปรดระบุว่าคุณต้องการใช้ไฟล์ในเครื่องแทน Google Cloud Secret Manager

da928c65ffa8ce15.png

  1. เริ่มชุดโปรแกรมจำลองในเครื่อง:
firebase emulators:start

ติดตั้งและทดสอบกับโปรเจ็กต์ Firebase จริง

คุณสามารถติดตั้งส่วนขยายของคุณในโปรเจ็กต์ Firebase จริงได้ ขอแนะนำให้ใช้โครงการทดสอบสำหรับการทดสอบของคุณ ใช้ขั้นตอนการทดสอบนี้หากคุณต้องการทดสอบโฟลว์ตั้งแต่ต้นจนจบของส่วนขยาย หรือหากชุดโปรแกรมจำลอง Firebase ยังไม่รองรับทริกเกอร์ของส่วนขยาย (ดู ตัวเลือกโปรแกรมจำลองส่วนขยาย ) ขณะนี้โปรแกรมจำลองรองรับฟังก์ชันที่เรียกใช้คำขอ HTTP และฟังก์ชันที่เรียกใช้เหตุการณ์ในเบื้องหลังสำหรับ Cloud Firestore, ฐานข้อมูลเรียลไทม์ และ Pub/Sub

  1. สร้างไดเร็กทอรีใหม่บนระบบโฮสต์ของคุณและเชื่อมต่อไดเร็กทอรีนั้นกับโปรเจ็กต์ Firebase ของคุณโดยใช้ firebase init
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. จากนั้น จากไดเร็กทอรีนั้น ให้รัน firebase ext:install เพื่อติดตั้งส่วนขยาย แทนที่ /path/to/extension ด้วยพาธสัมบูรณ์ไปยังไดเร็กทอรีที่มีไฟล์ extension.yaml ของคุณ การดำเนินการนี้จะเริ่มกระบวนการติดตั้งสำหรับส่วนขยายของคุณและสร้างไฟล์ .env ที่มีการกำหนดค่าของคุณก่อนที่จะพุชการกำหนดค่าไปที่ Firebase หรือไปยังโปรแกรมจำลอง
firebase ext:install /path/to/extension
  • เนื่องจากคุณต้องการปรับใช้กับ Firebase โดยตรง และต้องการใช้ Google Cloud Secret Manager คุณจึงต้อง เปิดใช้งาน Secret Manager API ก่อนติดตั้งส่วนขยาย
  1. ทำให้ใช้งานได้กับโปรเจ็กต์ Firebase ของคุณ
firebase deploy

ทดสอบส่วนขยาย

  1. หลังจากรัน firebase deploy หรือ firebase emulators:start ให้ไปที่แท็บ Firestore ของ คอนโซล Firebase หรือ webview ของ emulators ตามความเหมาะสม
  2. เพิ่มเอกสารลงในคอลเลกชันที่ระบุโดยฟิลด์ x และฟิลด์ y ในกรณีนี้ เอกสารที่อัปเดตจะอยู่ที่ u/{uid} โดยมีฟิลด์ x เป็น xv และฟิลด์ y เป็น yv

หน้าจอ Firebase Emulators เพื่อเพิ่มบันทึก Firestore

  1. หากคุณติดตั้งส่วนขยายได้สำเร็จ ส่วนขยายจะสร้างฟิลด์ใหม่ที่เรียกว่า hash ในเอกสารหลังจากที่คุณบันทึกทั้งสองฟิลด์

หน้าจอฐานข้อมูล Firestore จากโปรแกรมจำลองที่แสดงการเพิ่มแฮช

8. ขอแสดงความยินดี!

คุณได้แปลงฟังก์ชันคลาวด์แรกของคุณเป็นส่วนขยาย Firebase สำเร็จแล้ว!

คุณได้เพิ่มไฟล์ extension.yaml และกำหนดค่าเพื่อให้นักพัฒนาสามารถเลือกได้ว่าต้องการให้ส่วนขยายของคุณใช้งานได้อย่างไร จากนั้น คุณได้สร้างเอกสารสำหรับผู้ใช้ที่ให้คำแนะนำว่านักพัฒนาส่วนขยายควรทำอะไรก่อนตั้งค่าส่วนขยาย และขั้นตอนใดที่พวกเขาอาจต้องทำหลังจากติดตั้งส่วนขยายสำเร็จแล้ว

ตอนนี้คุณรู้ขั้นตอนสำคัญที่จำเป็นในการแปลงฟังก์ชัน Firebase ให้เป็นส่วนขยาย Firebase ที่สามารถแจกจ่ายได้

อะไรต่อไป?