Pierwsze kroki: pisanie, testowanie i wdrażanie pierwszych funkcji


Zacznij korzystać z Cloud Functions od tego samouczka. Zaczyna on od wymaganych zadań konfiguracyjnych i obejmuje tworzenie, testowanie i wdrażanie 2 powiązanych funkcji:

  • Funkcja dodawania wiadomości, która ujawnia adres URL, który akceptuje wartość tekstową i zapisuje ją w Cloud Firestore.
  • Funkcja „wielkie litery”, która uruchamia się przy zapisie w Cloud Firestore i przekształca tekst na wielkie litery.

Oto pełny przykładowy kod zawierający funkcje:

Node.js

// The Cloud Functions for Firebase SDK to create Cloud Functions and triggers.
const {logger} = require("firebase-functions");
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

// The Firebase Admin SDK to access Firestore.
const {initializeApp} = require("firebase-admin/app");
const {getFirestore} = require("firebase-admin/firestore");

initializeApp();

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addmessage = onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into Firestore using the Firebase Admin SDK.
  const writeResult = await getFirestore()
      .collection("messages")
      .add({original: original});
  // Send back a message that we've successfully written the message
  res.json({result: `Message with ID: ${writeResult.id} added.`});
});

// Listens for new messages added to /messages/:documentId/original
// and saves an uppercased version of the message
// to /messages/:documentId/uppercase
exports.makeuppercase = onDocumentCreated("/messages/{documentId}", (event) => {
  // Grab the current value of what was written to Firestore.
  const original = event.data.data().original;

  // Access the parameter `{documentId}` with `event.params`
  logger.log("Uppercasing", event.params.documentId, original);

  const uppercase = original.toUpperCase();

  // You must return a Promise when performing
  // asynchronous tasks inside a function
  // such as writing to Firestore.
  // Setting an 'uppercase' field in Firestore document returns a Promise.
  return event.data.ref.set({uppercase}, {merge: true});
});

Python

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore
import google.cloud.firestore

app = initialize_app()


@https_fn.on_request()
def addmessage(req: https_fn.Request) -> https_fn.Response:
    """Take the text parameter passed to this HTTP endpoint and insert it into
    a new document in the messages collection."""
    # Grab the text parameter.
    original = req.args.get("text")
    if original is None:
        return https_fn.Response("No text parameter provided", status=400)

    firestore_client: google.cloud.firestore.Client = firestore.client()

    # Push the new message into Cloud Firestore using the Firebase Admin SDK.
    _, doc_ref = firestore_client.collection("messages").add({"original": original})

    # Send back a message that we've successfully written the message
    return https_fn.Response(f"Message with ID {doc_ref.id} added.")


@firestore_fn.on_document_created(document="messages/{pushId}")
def makeuppercase(event: firestore_fn.Event[firestore_fn.DocumentSnapshot | None]) -> None:
    """Listens for new documents to be added to /messages. If the document has
    an "original" field, creates an "uppercase" field containg the contents of
    "original" in upper case."""

    # Get the value of "original" if it exists.
    if event.data is None:
        return
    try:
        original = event.data.get("original")
    except KeyError:
        # No "original" field, so do nothing.
        return

    # Set the "uppercase" field.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    event.data.reference.update({"uppercase": upper})

Informacje o samouczku

W tym przykładzie wybraliśmy funkcje aktywowane przez Cloud Firestore i HTTP, między innymi dlatego, że te aktywatory działające w tle można dokładnie przetestować za pomocą Pakietu emulatorów lokalnych Firebase. Ten zestaw narzędzi obsługuje też aktywatory baz danych czasu rzeczywistego, Cloud Storage, Pub/Sub, Auth i aktywatorów HTTP. Inne typy aktywatorów działających w tle, takie jak aktywatory Zdalnej konfiguracji i TestLab, można przetestować interaktywnie przy użyciu zestawów narzędzi nieopisanych na tej stronie.

Poniższe sekcje tego samouczka zawierają informacje o krokach wymaganych do skompilowania, przetestowania i wdrożenia przykładu.

Utwórz projekt Firebase

  1. W konsoli Firebase kliknij Dodaj projekt.

    • Aby dodać zasoby Firebase do istniejącego projektu Google Cloud, wpisz nazwę projektu lub wybierz go z menu.

    • Aby utworzyć nowy projekt, wpisz nazwę projektu. Możesz też opcjonalnie edytować identyfikator projektu wyświetlany pod jego nazwą.

  2. Jeśli pojawi się taka prośba, przeczytaj i zaakceptuj warunki korzystania z Firebase.

  3. Kliknij Dalej.

  4. (Opcjonalnie) Skonfiguruj Google Analytics w swoim projekcie, by zapewnić optymalne działanie każdej z tych usług Firebase:

    Wybierz istniejące konto Google Analytics lub utwórz nowe.

    Jeśli utworzysz nowe konto, wybierz lokalizację raportowania Analytics, a następnie zaakceptuj w swoim projekcie ustawienia udostępniania danych i warunki korzystania z Google Analytics.

  5. Kliknij Utwórz projekt (lub Dodaj Firebase, jeśli używasz istniejącego projektu Google Cloud).

Firebase automatycznie udostępnia zasoby dla Twojego projektu Firebase. Po zakończeniu tego procesu wyświetli się strona przeglądu Twojego projektu Firebase w konsoli Firebase.

Konfigurowanie środowiska i interfejsu wiersza poleceń Firebase

Node.js

Aby zapisywać funkcje, potrzebujesz środowiska Node.js, a do wdrażania funkcji w środowisku wykonawczym Cloud Functions będziesz potrzebować interfejsu wiersza poleceń Firebase. Do instalowania Node.js i npm zalecamy użycie Menedżera wersji węzłów.

Po zainstalowaniu Node.js i npm zainstaluj interfejs wiersza poleceń Firebase za pomocą preferowanej metody. Aby zainstalować interfejs wiersza poleceń przy użyciu npm, użyj:

npm install -g firebase-tools

Spowoduje to zainstalowanie dostępnego globalnie polecenia Firebase. Jeśli polecenie nie powiedzie się, być może trzeba zmienić uprawnienia npm. Aby zaktualizować aplikację firebase-tools do najnowszej wersji, uruchom to samo polecenie ponownie.

Python

Do zapisywania funkcji potrzebujesz środowiska Python, a do wdrażania funkcji w środowisku wykonawczym Cloud Functions będzie Ci potrzebny interfejs wiersza poleceń Firebase. Do odizolowania zależności zalecamy użycie venv. Obsługiwane są wersje 3.10 i 3.11 Pythona.

Po zainstalowaniu Pythona zainstaluj interfejs wiersza poleceń Firebase za pomocą preferowanej metody.

Zainicjuj projekt

Gdy zainicjujesz pakiet Firebase SDK dla Cloud Functions, utworzysz pusty projekt zawierający zależności i krótki przykładowy kod. Jeśli używasz środowiska Node.js, do tworzenia funkcji możesz wybrać TypeScript lub JavaScript. Na potrzeby tego samouczka musisz też zainicjować Cloud Firestore.

Aby zainicjować projekt:

  1. Uruchom firebase login, aby zalogować się w przeglądarce i uwierzytelnić interfejs wiersza poleceń Firebase.
  2. Otwórz katalog projektu Firebase.
  3. Uruchom firebase init firestore. W tym samouczku po wyświetleniu prośby o reguły Firestore i pliki indeksu możesz zaakceptować wartości domyślne. Jeśli ta usługa nie była jeszcze używana w tym projekcie, musisz też wybrać tryb początkowy i lokalizację Firestore zgodnie z opisem w sekcji Pierwsze kroki z Cloud Firestore.
  4. Uruchom firebase init functions. Interfejs wiersza poleceń prosi o wybranie istniejącej bazy kodu lub zainicjowanie nowej bazy i nadanie nowej nazwy. Na początek wystarczy pojedyncza baza kodu w domyślnej lokalizacji. Później, w miarę rozwoju implementacji, warto uporządkować funkcje w bazach kodu.
  5. Interfejs wiersza poleceń udostępnia te opcje obsługi języków:

    • JavaScript
    • TypeScript
    • Python

    Na potrzeby tego samouczka wybierz JavaScript lub Python. Informacje na temat tworzenia kodu w języku TypeScript znajdziesz w sekcji poświęconej funkcji zapisu w języku TypeScript.

  6. Interfejs wiersza poleceń umożliwia instalowanie zależności. Możesz ją odrzucić, jeśli chcesz zarządzać zależnościami w inny sposób.

Gdy te polecenia zostaną ukończone, struktura projektu będzie wyglądać tak:

Node.js

myproject
+- .firebaserc    # Hidden file that helps you quickly switch between
|                 # projects with `firebase use`
|
+- firebase.json  # Describes properties for your project
|
+- functions/     # Directory containing all your functions code
      |
      +- .eslintrc.json  # Optional file containing rules for JavaScript linting.
      |
      +- package.json  # npm package file describing your Cloud Functions code
      |
      +- index.js      # Main source file for your Cloud Functions code
      |
      +- node_modules/ # Directory where your dependencies (declared in
                        # package.json) are installed

W przypadku Node.js plik package.json utworzony podczas inicjowania zawiera ważny klucz: "engines": {"node": "18"}. Określa wersję Node.js do zapisywania i wdrażania funkcji. Możesz wybrać inne obsługiwane wersje.

Python

myproject
+- .firebaserc    # Hidden file that helps you quickly switch between
|                 # projects with `firebase use`
|
+- firebase.json  # Describes properties for your project
|
+- functions/     # Directory containing all your functions code
      |
      +- main.py      # Main source file for your Cloud Functions code
      |
      +- requirements.txt  #  List of the project's modules and packages 
      |
      +- venv/ # Directory where your dependencies are installed

Zaimportuj wymagane moduły i zainicjuj aplikację

Po ukończeniu zadań konfiguracyjnych możesz otworzyć katalog źródłowy i zacząć dodawać kod zgodnie z opisem w następnych sekcjach. Na potrzeby tego przykładu Twój projekt musi zaimportować moduły Cloud Functions i pakietu Admin SDK. Dodaj do pliku źródłowego wiersze podobne do tych:

Node.js

// The Cloud Functions for Firebase SDK to create Cloud Functions and triggers.
const {logger} = require("firebase-functions");
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

// The Firebase Admin SDK to access Firestore.
const {initializeApp} = require("firebase-admin/app");
const {getFirestore} = require("firebase-admin/firestore");

initializeApp();

Python

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore
import google.cloud.firestore

app = initialize_app()

Te wiersze wczytują wymagane moduły i inicjują instancję aplikacji admin, w której można wprowadzać zmiany w Cloud Firestore. Wszędzie tam, gdzie dostępna jest obsługa pakietu Admin SDK, tak samo jak w przypadku FCM, uwierzytelniania i Bazy danych czasu rzeczywistego Firebase, zapewnia ona skuteczny sposób integracji Firebase z wykorzystaniem Cloud Functions.

Interfejs wiersza poleceń Firebase automatycznie instaluje moduły Firebase Admin SDK i Firebase SDK dla Cloud Functions po zainicjowaniu projektu. Więcej informacji o dodawaniu bibliotek zewnętrznych do projektu znajdziesz w artykule o obsłudze zależności.

Dodawanie funkcji „dodaj wiadomość”

W przypadku funkcji „add message” (dodaj wiadomość) dodaj do pliku źródłowego te wiersze:

Node.js

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addmessage = onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into Firestore using the Firebase Admin SDK.
  const writeResult = await getFirestore()
      .collection("messages")
      .add({original: original});
  // Send back a message that we've successfully written the message
  res.json({result: `Message with ID: ${writeResult.id} added.`});
});

Python

@https_fn.on_request()
def addmessage(req: https_fn.Request) -> https_fn.Response:
    """Take the text parameter passed to this HTTP endpoint and insert it into
    a new document in the messages collection."""
    # Grab the text parameter.
    original = req.args.get("text")
    if original is None:
        return https_fn.Response("No text parameter provided", status=400)

    firestore_client: google.cloud.firestore.Client = firestore.client()

    # Push the new message into Cloud Firestore using the Firebase Admin SDK.
    _, doc_ref = firestore_client.collection("messages").add({"original": original})

    # Send back a message that we've successfully written the message
    return https_fn.Response(f"Message with ID {doc_ref.id} added.")

Funkcja „add message” (dodaj wiadomość) to punkt końcowy HTTP. Każde żądanie wysyłane do punktu końcowego powoduje, że obiekty żądań i odpowiedzi są przekazywane do modułu obsługi żądań na Twojej platformie (onRequest() lub on_request).

Funkcje HTTP są synchroniczne (podobnie do funkcji wywoływanych), więc musisz jak najszybciej wysłać odpowiedź i odłożyć pracę w Cloud Firestore. Funkcja HTTP „add message” (dodaj wiadomość) przekazuje wartość tekstową do punktu końcowego HTTP i wstawia ją do bazy danych pod ścieżką /messages/:documentId/original.

Dodaj funkcję „wielkie litery”

W przypadku funkcji „wielkie litery” dodaj do pliku źródłowego te wiersze:

Node.js

// Listens for new messages added to /messages/:documentId/original
// and saves an uppercased version of the message
// to /messages/:documentId/uppercase
exports.makeuppercase = onDocumentCreated("/messages/{documentId}", (event) => {
  // Grab the current value of what was written to Firestore.
  const original = event.data.data().original;

  // Access the parameter `{documentId}` with `event.params`
  logger.log("Uppercasing", event.params.documentId, original);

  const uppercase = original.toUpperCase();

  // You must return a Promise when performing
  // asynchronous tasks inside a function
  // such as writing to Firestore.
  // Setting an 'uppercase' field in Firestore document returns a Promise.
  return event.data.ref.set({uppercase}, {merge: true});
});

Python

@firestore_fn.on_document_created(document="messages/{pushId}")
def makeuppercase(event: firestore_fn.Event[firestore_fn.DocumentSnapshot | None]) -> None:
    """Listens for new documents to be added to /messages. If the document has
    an "original" field, creates an "uppercase" field containg the contents of
    "original" in upper case."""

    # Get the value of "original" if it exists.
    if event.data is None:
        return
    try:
        original = event.data.get("original")
    except KeyError:
        # No "original" field, so do nothing.
        return

    # Set the "uppercase" field.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    event.data.reference.update({"uppercase": upper})

Funkcja „make wielkimi literami” jest wykonywana podczas zapisywania w Cloud Firestore i definiuje dokument, na którym ma być nasłuchiwany. Ze względu na skuteczność należy podawać jak najbardziej szczegółowe informacje.

Nawiasy klamrowe (np. {documentId}) otaczają „parametry”, czyli symbole wieloznaczne, które ujawniają dopasowane dane w wywołaniu zwrotnym. Cloud Firestore uruchamia wywołanie zwrotne po każdym dodaniu nowych wiadomości.

W Node.js funkcje oparte na zdarzeniach, takie jak zdarzenia Cloud Firestore, są asynchroniczne. Funkcja wywołania zwrotnego powinna zwracać wartość null, obiekt lub Promise. Jeśli nie zwrócisz niczego, funkcja przekroczy limit czasu, co zasygnalizuje błąd. Następnie zostanie ponowiona. Zapoznaj się z sekcją Synchronizacja, asynchroniczne i obietnice.

Emuluj wykonywanie funkcji

Pakiet emulatorów lokalnych Firebase pozwala tworzyć i testować aplikacje na komputerze lokalnym, zamiast wdrażać je w projekcie Firebase. Zdecydowanie zalecamy testy lokalne w trakcie programowania, m.in. dlatego, że zmniejsza to ryzyko wystąpienia błędów w kodowaniu, które mogą spowodować koszty w środowisku produkcyjnym (np. w pętli nieskończonej).

Aby emulować funkcje:

  1. Uruchom firebase emulators:start i sprawdź dane wyjściowe adresu URL interfejsu Pakietu emulatorów. Domyślnie jest to localhost:4000, ale może być hostowany na innym porcie na komputerze. Wpisz ten URL w przeglądarce, by otworzyć interfejs Pakietu emulatorów.

  2. Sprawdź dane wyjściowe polecenia firebase emulators:start pod kątem adresu URL funkcji HTTP. Będzie on wyglądał podobnie do http://localhost:5001/MY_PROJECT/us-central1/addMessage z tymi różnicami:

    1. Pole MY_PROJECT zostanie zastąpione identyfikatorem projektu.
    2. Port może się różnić na komputerze lokalnym.
  3. Dodaj ciąg zapytania ?text=uppercaseme na końcu adresu URL funkcji. Powinien wyglądać mniej więcej tak: http://localhost:5001/MY_PROJECT/us-central1/addMessage?text=uppercaseme. Opcjonalnie możesz zmienić komunikat „wielkie litery” na komunikat niestandardowy.

  4. Utwórz nową wiadomość, otwierając adres URL w nowej karcie przeglądarki.

  5. Zobacz efekty działania funkcji w interfejsie Pakietu emulatorów:

    1. Na karcie Logi powinny pojawić się nowe logi wskazujące, że funkcje HTTP zostały uruchomione:

      i functions: Beginning execution of "addMessage"

      i functions: Beginning execution of "makeUppercase"

    2. Na karcie Firestore powinien być widoczny dokument zawierający oryginalną wiadomość oraz jej wersję pisaną wielkimi literami (jeśli wcześniejsza wiadomość była pisana wielkimi literami, będzie wyświetlana WIELKA LICZBA).

Wdrażanie funkcji w środowisku produkcyjnym

Gdy funkcje w emulatorze działają zgodnie z oczekiwaniami, możesz je wdrażać, testować i uruchamiać w środowisku produkcyjnym. Pamiętaj, że aby można było wdrożyć projekt w środowisku produkcyjnym, musi on być objęty abonamentem Blaze. Sprawdź cennik Cloud Functions.

Aby ukończyć samouczek, wdróż funkcje, a następnie je wykonaj.

  1. Aby wdrożyć funkcje, uruchom to polecenie:

     firebase deploy --only functions
     

    Po uruchomieniu tego polecenia interfejs wiersza poleceń Firebase wyświetli adres URL wszystkich punktów końcowych funkcji HTTP. W terminalu powinien pojawić się wiersz podobny do tego:

    Function URL (addMessage): https://us-central1-MY_PROJECT.cloudfunctions.net/addMessage
    

    Adres URL zawiera identyfikator projektu oraz region dla funkcji HTTP. Na razie nie musisz się tym przejmować, ale niektóre produkcyjne funkcje HTTP powinny określać lokalizację, aby zminimalizować opóźnienia w sieci.

    Jeśli wystąpią błędy dostępu, takie jak „Nie można autoryzować dostępu do projektu”, spróbuj sprawdzić aliasy projektu.

  2. Korzystając z adresu URL wyjściowego interfejsu wiersza poleceń, dodaj tekstowy parametr zapytania i otwórz go w przeglądarce:

    https://us-central1-MY_PROJECT.cloudfunctions.net/addMessage?text=uppercasemetoo
    

    Funkcja uruchamia przeglądarkę i przekierowuje ją do konsoli Firebase w lokalizacji bazy danych, w której jest przechowywany ciąg tekstowy. To zdarzenie zapisu aktywuje funkcję „make bigcase”, która zapisuje wersję ciągu znaków wielkimi literami.

Po wdrożeniu i wykonaniu funkcji możesz wyświetlić logi w konsoli Google Cloud. Jeśli musisz usunąć funkcje w środowisku programistycznym lub produkcyjnym, użyj interfejsu wiersza poleceń Firebase.

W środowisku produkcyjnym możesz optymalizować wydajność funkcji i kontrolować koszty przez ustawienie minimalnej i maksymalnej liczby instancji, które mają zostać uruchomione. Więcej informacji o tych opcjach środowiska wykonawczego znajdziesz w artykule o zarządzaniu zachowaniem skalowania.

Dalsze kroki

Z tej dokumentacji dowiesz się więcej o zarządzaniu funkcjami w Cloud Functions oraz o obsłudze wszystkich typów zdarzeń obsługiwanych przez Cloud Functions.

Aby dowiedzieć się więcej o Cloud Functions, możesz też wykonać te czynności: