Как расширить возможности SQL Connect с помощью Cloud Functions

С помощью Cloud Functions for Firebase вы можете обрабатывать события в Firebase SQL Connect. Cloud Functions позволяет выполнять серверный код в ответ на события, например на выполнение мутации в сервисе SQL Connect. Это позволяет добавлять собственную логику без развертывания собственных серверов.

Примеры использования

  • Синхронизация данных. Репликация или синхронизация данных с другими системами (например, Cloud Firestore, BigQuery или внешними API) после изменения.

  • Асинхронные рабочие процессы. Запускайте длительные процессы, такие как обработка изображений или агрегирование данных, после изменения базы данных.

  • Взаимодействие с пользователями. Отправляйте пользователям электронные письма или Cloud Messaging-уведомления после определенного события изменения в приложении, например создания аккаунта.

Как настроить триггер функции при изменении SQL Connect

Вы можете активировать функцию при каждом выполнении изменения SQL Connect с помощью обработчика событий onMutationExecuted. Этот триггер срабатывает при выполнении мутации.

Простая функция события изменения DOM

Ниже приведен простой пример функции, которая регистрирует сведения о любом изменении, выполненном в сервисе SQL Connect.

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)

Если триггер срабатывает при любых изменениях в проекте, не выполняйте никаких изменений в обработчике триггера, иначе вы вызовете бесконечный цикл. Если вы хотите выполнить изменения в триггере события, используйте описанные ниже параметры фильтрации и убедитесь, что изменение не запускает само себя.

Как указать местоположение функции

Чтобы события запускали функцию, местоположение функции должно совпадать с местоположением сервиса SQL Connect. По умолчанию регион функции – us-central1.

Node.js

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

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

Python

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

Введите фильтр

Обработчик onMutationExecuted можно настроить так, чтобы он фильтровал события по определенным атрибутам. Это полезно, если вы хотите запускать функцию только для определенных изменений.

Вы можете отфильтровать список по следующим параметрам: service, connector и operation.

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

Тип и идентификатор аутентификации будут заполнены следующим образом:

Изменение инициировано authtype authid
Конечный пользователь, прошедший аутентификацию app_user UID токена Firebase Auth
Неаутентифицированный конечный пользователь unauthenticated пусто
Admin SDK, выдающий себя за конечного пользователя app_user UID токена Firebase Auth пользователя, от имени которого выполняется действие.
Admin SDK имитирует неаутентифицированный запрос unauthenticated пусто
Admin 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 Полезная нагрузка события SQL Connect. Подробная информация приведена в следующем разделе.

Полезная нагрузка данных

Объект MutationEventData содержит полезную нагрузку события SQL 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 – объект, содержащий переменные, которые были переданы в мутацию.
  • 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 Firestore или Realtime Database, событие SQL Connect не предоставляет снимок данных "до". Поскольку SQL Connect передает запросы в базовую базу данных, снимок данных "до" не может быть получен транзакционно. Вместо этого у вас есть доступ к аргументам, отправленным в мутацию, и данным, которые она вернула.

В частности, вы не можете сравнивать снимки "до" и "после", чтобы избежать бесконечных циклов, в которых триггер события вызывает то же самое событие. Если вам необходимо выполнить изменение из функции, активируемой событием изменения DOM, используйте фильтры событий и убедитесь, что изменение не может активировать само себя, даже косвенно.