Déclencheurs Firebase Realtime Database

Avec Cloud Run Functions, vous pouvez gérer les événements dans Firebase Realtime Database dans le même projet Google Cloud que la fonction. Cloud Run Functions vous permet d'exécuter des opérations de base de données avec des droits d'administrateur complets et garantit que chaque modification de la base de données est traitée individuellement. Vous pouvez apporter des modifications à Firebase Realtime Database via le SDK Admin Firebase.

Dans un cycle de vie typique, une fonction Firebase Realtime Database effectue les opérations suivantes :

  1. Attend les modifications apportées à un emplacement de base de données particulier.

  2. Se déclenche lorsqu'un événement se produit et exécute ses tâches.

  3. Reçoit un objet de données qui contient un instantané des données stockées dans le document spécifié.

Types d'événement

Cloud Functions vous permet de gérer les événements de base de données à deux niveaux de spécificité. Vous pouvez écouter uniquement les événements de création, de mise à jour ou de suppression ou bien écouter toute modification apportée à un chemin d'accès. Cloud Run Functions accepte les types d'événements suivants pour Realtime Database :

Type d'événement Déclencheur
providers/google.firebase.database/eventTypes/ref.write Déclenché lors de tout événement de mutation : à la création, la mise à jour ou la suppression de données dans Realtime Database.
providers/google.firebase.database/eventTypes/ref.create (par défaut) Déclenché lors de la création de données dans Realtime Database.
providers/google.firebase.database/eventTypes/ref.update Déclenché lors de la mise à jour de données dans Realtime Database.
providers/google.firebase.database/eventTypes/ref.delete Déclenché lors de la suppression de données dans Realtime Database.

Spécifier le chemin d'accès et l'instance de la base de données

Pour contrôler le moment et le lieu du déclenchement de votre fonction, vous devez spécifier un chemin d'accès et éventuellement une instance de base de données.

Chemin

Les spécifications de chemin d'accès correspondent à toutes les écritures qui touchent un chemin d'accès, y compris les écritures se trouvant en dessous. Si le chemin d'accès de votre fonction est défini sur /foo/bar, il correspond aux événements de ces deux emplacements :

 /foo/bar
 /foo/bar/baz/really/deep/path

Dans les deux cas, Firebase interprète que l'événement se produit à /foo/bar, et les données d'événement incluent les anciennes et les nouvelles données se trouvant à /foo/bar. Si les données d'événement risquent d'être volumineuses, envisagez d'utiliser plusieurs fonctions sur des chemins d'accès plus profonds au lieu d'utiliser une seule fonction près de la racine de votre base de données. Pour des performances optimales, demandez uniquement des données au niveau le plus profond possible.

Vous pouvez spécifier un composant de chemin d'accès en tant que caractère générique en l'entourant d'accolades. foo/{bar} correspond à n'importe quel enfant de /foo. Les valeurs de ces composants à caractère génériques sont disponibles dans l'objet event.params de votre fonction. Dans cet exemple, la valeur est disponible sous le nom event.params.bar.

Les chemins d'accès contenant des caractères génériques peuvent correspondre à plusieurs événements d'une seule écriture. Une insertion de :

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

correspond au chemin d'accès /foo/{bar} deux fois : une fois avec "hello": "world" et une autre fois avec "firebase": "functions".

Instance

Lorsque vous utilisez la console Google Cloud, l'instance de base de données doit être spécifiée.

Avec Google Cloud CLI, l'instance doit être spécifiée dans la chaîne --trigger-resource.

Par exemple, dans votre chaîne --trigger-resource, la commande suivante serait utilisée :

--trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/PATH

Structure de l'événement

Lors de la gestion d'un événement Realtime Database, l'objet data contient deux propriétés qui sont fournies au format JSON :

  • data est un instantané des données pris avant l'événement ayant déclenché la fonction.

  • delta est un instantané des données pris après l'événement ayant déclenché la fonction.

Exemple de code

Node.js

/**
 * Background Function triggered by a change to a Firebase RTDB reference.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Object} context The Cloud Functions event context.
 */
exports.helloRTDB = (event, context) => {
  const triggerResource = context.resource;

  console.log(`Function triggered by change to: ${triggerResource}`);
  console.log(`Admin?: ${!!context.auth.admin}`);
  console.log('Delta:');
  console.log(JSON.stringify(event.delta, null, 2));
};

Python

import json

def hello_rtdb(data, context):
    """Triggered by a change to a Firebase RTDB reference.
    Args:
        data (dict): The event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """
    trigger_resource = context.resource

    print("Function triggered by change to: %s" % trigger_resource)
    print("Admin?: %s" % data.get("admin", False))
    print("Delta:")
    print(json.dumps(data["delta"]))

Go


// Package p contains a Cloud Function triggered by a Firebase Realtime Database
// event.
package p

import (
	"context"
	"fmt"
	"log"

	"cloud.google.com/go/functions/metadata"
)

// RTDBEvent is the payload of a RTDB event.
type RTDBEvent struct {
	Data  interface{} `json:"data"`
	Delta interface{} `json:"delta"`
}

// HelloRTDB handles changes to a Firebase RTDB.
func HelloRTDB(ctx context.Context, e RTDBEvent) error {
	meta, err := metadata.FromContext(ctx)
	if err != nil {
		return fmt.Errorf("metadata.FromContext: %w", err)
	}
	log.Printf("Function triggered by change to: %v", meta.Resource)
	log.Printf("%+v", e)
	return nil
}

Java

import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.logging.Logger;

public class FirebaseRtdb implements RawBackgroundFunction {
  private static final Logger logger = Logger.getLogger(FirebaseRtdb.class.getName());

  // Use GSON (https://github.com/google/gson) to parse JSON content.
  private static final Gson gson = new Gson();

  @Override
  public void accept(String json, Context context) {
    logger.info("Function triggered by change to: " + context.resource());

    JsonObject body = gson.fromJson(json, JsonObject.class);

    boolean isAdmin = false;
    if (body != null && body.has("auth")) {
      JsonObject authObj = body.getAsJsonObject("auth");
      isAdmin = authObj.has("admin") && authObj.get("admin").getAsBoolean();
    }

    logger.info("Admin?: " + isAdmin);

    if (body != null && body.has("delta")) {
      logger.info("Delta:");
      logger.info(body.get("delta").toString());
    }
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Firebase.Database.V1;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseRtdb;

public class Function : ICloudEventFunction<ReferenceEventData>
{
    private readonly ILogger _logger;

    public Function(ILogger<Function> logger) =>
        _logger = logger;

    public Task HandleAsync(CloudEvent cloudEvent, ReferenceEventData data, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Function triggered by change to {subject}", cloudEvent.Subject);
        _logger.LogInformation("Delta: {delta}", data.Delta);

        // In this example, we don't need to perform any asynchronous operations, so the
        // method doesn't need to be declared async.
        return Task.CompletedTask;
    }
}

Ruby

require "functions_framework"

# Triggered by a change to a Firebase RTDB document.
FunctionsFramework.cloud_event "hello_rtdb" do |event|
  # Event-triggered Ruby functions receive a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  # The Firebase event payload can be obtained from the `data` field.
  payload = event.data

  logger.info "Function triggered by change to: #{event.source}"
  logger.info "Admin?: #{payload.fetch 'admin', false}"
  logger.info "Delta: #{payload['delta']}"
end

PHP


use Google\CloudFunctions\CloudEvent;

function firebaseRTDB(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');

    fwrite($log, 'Event: ' . $cloudevent->getId() . PHP_EOL);

    $data = $cloudevent->getData();
    $resource = $data['resource'] ?? '<null>';

    fwrite($log, 'Function triggered by change to: ' . $resource . PHP_EOL);

    $isAdmin = isset($data['auth']['admin']) && $data['auth']['admin'] == true;

    fwrite($log, 'Admin?: ' . var_export($isAdmin, true) . PHP_EOL);
    fwrite($log, 'Delta: ' . json_encode($data['delta'] ?? '') . PHP_EOL);
}

Déployer votre fonction

La commande gcloud suivante déploie une fonction qui est déclenchée par les événements create sur le chemin d'accès /messages/{pushId}/original :

gcloud functions deploy FUNCTION_NAME \
  --no-gen2 \
  --entry-point ENTRY_POINT \
  --trigger-event providers/google.firebase.database/eventTypes/ref.create \
  --trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/messages/{pushId}/original \
  --runtime RUNTIME
Argument Description
FUNCTION_NAME Nom enregistré de la fonction Cloud Run que vous déployez. Il peut s'agir du nom d'une fonction dans votre code source ou d'une chaîne arbitraire. Si FUNCTION_NAME est une chaîne arbitraire, vous devez alors inclure l'option --entry-point.
--entry-point ENTRY_POINT Nom d'une fonction ou d'une classe dans votre code source. Ce paramètre est facultatif, sauf si vous n'avez pas utilisé FUNCTION_NAME pour spécifier quelle fonction de votre code source exécuter lors du déploiement. Dans ce cas, vous devez utiliser --entry-point pour fournir le nom de la fonction exécutable.
--trigger-event NAME Nom du type d'événement que la fonction souhaite recevoir. Dans ce cas, il s'agit de l'un des éléments suivants : écrire, créer, mettre à jour ou supprimer.
--trigger-resource NAME Chemin d'accès complet de la base de données sur lequel la fonction écoutera. Il doit respecter le format suivant : projects/_/instances/DATABASE_INSTANCE/refs/PATH.
--runtime RUNTIME Nom de l'environnement d'exécution que vous utilisez. Pour obtenir une liste complète, consultez la documentation de référence sur gcloud.