使用 Cloud Functions 扩展 Data Connect

使用 Cloud Functions for Firebase,您可以处理 Firebase Data Connect 中的事件。Cloud Functions 允许您运行服务器端代码以响应事件,例如在您的 Data Connect 服务中执行 mutation。这样一来,您无需部署自己的服务器即可添加自定义逻辑。

常见使用场景

  • 数据同步:在发生变更后,将数据复制或同步到其他系统(如Cloud Firestore、BigQuery 或外部 API)。

  • 异步工作流:在数据库更改后启动长时间运行的进程,例如图像处理或数据聚合。

  • 用户互动: 在您的应用程序中发生特定变更事件(例如创建账号)后,向用户发送电子邮件或Cloud Messaging通知。

Data Connect 突变时触发函数

您可以使用 onMutationExecuted 事件处理程序在执行 Data Connect 变更时触发一个函数。此触发器在执行 mutation 时发生。

基本突变事件函数

以下基本示例是一个函数,用于记录在您的 Data Connect 服务中执行的任何 mutation 的详细信息:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const logMutation = onMutationExecuted(
  {
    /* Trigger on all mutations, spanning all services and connectors
       in us-central1 */
  },
  (event) => {
    logger.info("A mutation was executed!", {
      data: event.data,
    });
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed()
def log_mutation(event: dataconnect_fn.Event):
  logger.info("A mutation was executed!", event.data)

当触发器基于项目中的所有突变触发时,您不得在触发器处理程序中执行任何突变,否则会导致无限循环。如果要对事件触发器执行变更操作,请使用下面描述的过滤选项,并注意不要触发变更操作本身。

设置函数位置

功能位置必须与Data Connect服务地点用于触发该函数的事件。默认情况下,函数区域为 us-central1

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutationRegionOption = onMutationExecuted(
  {
    region: "europe-west1"  // Set if Data Connect service location is not us-central1
  },
  (event) => { /* ... */ }
);

Python

@dataconnect_fn.on_mutation_executed(
  region="europe-west1"  # Set if Data Connect service location is not us-central1
)
def mutation_executed_handler_region_option(event: dataconnect_fn.Event):
  pass

过滤事件

onMutationExecuted 处理程序可以配置选项,以根据特定属性过滤事件。如果您只想针对特定突变触发函数,这会非常有用。

您可以按serviceconnectoroperation进行过滤:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

// Trigger this function only for the CreateUser mutation
// in the users connector of the myAppService service.
export const onUserCreate = onMutationExecuted(
  {
    service: "myAppService",
    connector: "users",
    operation: "CreateUser",
  },
  (event) => {
    logger.info("A new user was created!", event.data);
    // Add logic here: for example, sending a welcome email.
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def on_user_create(event: dataconnect_fn.Event):
  logger.info("A new user was created!", event.data)

通配符和捕获组

您可以使用通配符和捕获组来根据多个值过滤触发器。捕获到的所有组都可以在 event.params 中使用。有关更多信息,请参阅了解路径模式

示例:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

// Trigger on all operations that match the pattern `User*`, on any service and
// connector.
export const onMutationWildcards = onMutationExecuted(
  {
    operation: "User*",
  },
  (event) => {}
);

// Trigger on all operations that match the pattern `User*`, on any service and
// connector. Capture the operation name in the variable `op`.
export const onMutationCaptureWildcards = onMutationExecuted(
  {
    operation: "{op=User*}",
  },
  (event) => {
    // `event.params.op` contains the operation name.
  }
);

// Trigger on all operations on the service `myAppService`. Capture the
// operation name in the variable `operation`.
export const onMutationCaptures = onMutationExecuted(
  {
    service: "myAppService",
    operation: "{operation}",
  },
  (event) => {
    // `event.params.operation` contains the operation name.
  }
);

Python

from firebase_functions import dataconnect_fn

# Trigger on all operations that match the pattern `User*`, on any service and
# connector.
@dataconnect_fn.on_mutation_executed(
  operation="User*"
)
def on_mutation_wildcards(event: dataconnect_fn.Event):
  pass

# Trigger on all operations that match the pattern `User*`, on any service and
# connector. Capture the operation name in the variable `op`.
@dataconnect_fn.on_mutation_executed(
  operation="{op=User*}"
)
def on_mutation_capture_wildcards(event: dataconnect_fn.Event):
  # `event.params["op"]` contains the operation name.
  pass

# Trigger on all operations on the service `myAppService`. Capture the
# operation name in the variable `operation`.
@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  operation="{operation}"
)
def on_mutation_captures(event: dataconnect_fn.Event):
  # `event.params["operation"]` contains the operation name.
  pass

访问用户身份验证信息

您可以访问有关触发事件的正文的用户身份验证信息。有关身份验证上下文中可用数据的更多信息,请参阅 身份验证上下文

以下示例演示如何检索身份验证信息:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutation = onMutationExecuted(
  { operation: "MyMutation" },
  (event) => {
    // mutationExecuted event provides authType and authId:
    // event.authType
    // event.authId
  }
);

Python

from firebase_functions import dataconnect_fn

@dataconnect_fn.on_mutation_executed(operation="MyMutation")
def mutation_executed_handler(event: dataconnect_fn.Event):
  # mutationExecuted event provides auth_type and auth_id, which are accessed as follows
  # event.auth_type
  # event.auth_id
  pass

身份验证类型和身份验证 ID 将按如下方式填充:

突变由发起 authtype authid
已认证的最终用户 app_user Firebase Auth 令牌 UID
未经身份验证的最终用户 unauthenticated 空白
Admin SDK 模拟最终用户 app_user 被模拟用户的 Firebase Auth 令牌 UID
Admin SDK 模拟未经身份验证的请求 unauthenticated 空白
具有完整权限的管理员 SDK admin 空白

访问活动数据

传递给函数的 CloudEvent 对象包含有关触发该函数的事件的信息。

事件属性

属性 类型 说明
id string 事件的唯一标识符。
source string 生成事件的连接器资源(例如 //firebasedataconnect.googleapis.com/projects/*/locations/*/services/*/connectors/*)。
specversion string CloudEvents 规范版本(例如 "1.0")。
type string 事件的类型:google.firebase.dataconnect.connector.v1.mutationExecuted
time string 事件生成时的时间戳(ISO 8601 格式)。
subject string 可选。有关事件上下文的额外信息,例如操作名称。
params object 捕获的路径模式的地图。
authType string 一个枚举,表示触发事件的正文的类型。
authId string 触发事件的主账号的唯一标识符。
data MutationEventData Data Connect 事件的有效载荷。请参阅下一节。

数据有效载荷

MutationEventData 对象包含 Data Connect 事件的有效载荷:

{
  // ...
  "authType": // ...
  "data": {
    "payload": {
      "variables": {
        "userId": "user123",
        "updateData": {
          "displayName": "New Name"
        }
      },
      "data": {
        "updateUser": {
          "id": "user123",
          "displayName": "New Name",
          "email": "user@example.com"
        }
      },
      "errors": []
    }
  }
}
  • payload.variables: 包含传递给 mutation 的变量的对象。
  • payload.data:包含相应变异返回的数据的对象。
  • payload.errors: 突变执行过程中发生的任何错误的数组。如果变异成功,则此数组为空。

示例

以下是如何访问突变变量和返回数据的方法:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const processNewUserData = onMutationExecuted(
  {
    "service": "myAppService",
    "connector": "users",
    "operation": "CreateUser",
  },
  (event) => {
    // The variables passed to the mutation
    const mutationVariables = event.data.payload.variables;

    // The data returned by the mutation
    const returnedData = event.data.payload.data;

    logger.info("Processing mutation with variables:", mutationVariables);
    logger.info("Mutation returned:", returnedData);

    // ... your custom logic here
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def process_new_user_data(event: dataconnect_fn.Event):
  # The variables passed to the mutation
  mutation_vars = event.data.payload.variables
  # The data returned by the mutation
  returned_data = event.data.payload.data

  logger.info("Processing mutation with variables:", mutationVariables)
  logger.info("Mutation returned", returnedData)

  # ... your custom logic here

请注意,与其他一些数据库触发器(如 Cloud FirestoreRealtime Database)不同,Data Connect 事件不提供数据的“之前”快照。因为 Data Connect 代理对底层数据库的请求,所以无法通过事务获取数据的“之前”快照。相反,您可以访问传递给 mutation 的参数以及它返回的数据。

由此产生的一个后果是,你不能使用比较“之前”和“之后”快照的策略来避免无限循环,在无限循环中,一个事件触发器会触发同一个事件。如果必须从由突变事件触发的函数中执行突变,请使用事件过滤器,并注意确保任何突变都不会触发自身,即使是间接触发。