Configurar y recibir notificaciones push

Puedes usar los métodos de la colección Watches para recibir notificaciones cuando cambien los datos en los formularios. En esta página, se proporciona una descripción general conceptual y las instrucciones para configurar y recibir notificaciones push.

Descripción general

La función de notificaciones push de la API de Google Forms permite que las aplicaciones se suscriban a las notificaciones cuando cambian los datos en los formularios. Las notificaciones se envían a un tema de Cloud Pub/Sub, por lo general, a los pocos minutos de que se produce el cambio.

Para recibir notificaciones push, debes configurar un tema de Cloud Pub/Sub y proporcionar el nombre de ese tema cuando crees un objeto de observación para el tipo de evento adecuado.

A continuación, se incluyen las definiciones de los conceptos clave que se usan en esta documentación:

  • Un destino es un lugar al que se envían notificaciones. El único destino admitido es un tema de Cloud Pub/Sub.
  • Un tipo de evento es una categoría de notificaciones a la que se puede suscribir una aplicación de terceros.
  • Una observación es una instrucción para que la API de Forms envíe notificaciones sobre un tipo de evento específico en un formulario determinado a un destino.

Una vez que creas una observación para un tipo de evento en un formulario en particular, el destino de esa observación (que es un tema de Cloud Pub/Sub) recibe notificaciones de esos eventos en ese formulario hasta que vence la observación. El reloj dura una semana, pero puedes extenderlo en cualquier momento antes de que venza si realizas una solicitud a watches.renew().

Tu tema de Cloud Pub/Sub solo recibe notificaciones sobre los formularios que puedes ver con las credenciales que proporcionas. Por ejemplo, si el usuario revoca el permiso de tu aplicación o pierde el acceso de edición a un formulario observado, ya no se enviarán notificaciones.

Tipos de eventos disponibles

Actualmente, la API de Formularios de Google ofrece dos categorías de eventos:

  • EventType.SCHEMA, que notifica sobre los cambios en el contenido y la configuración de un formulario.
  • EventType.RESPONSES, que notifica cuando se envían respuestas de formularios (tanto nuevas como actualizadas).

Respuestas a notificaciones

Las notificaciones se codifican con JSON y contienen lo siguiente:

  • ID del formulario de activación
  • ID del reloj que activó la acción
  • Es el tipo de evento que activó la notificación.
  • Otros campos establecidos por Cloud Pub/Sub, como messageId y publishTime

Las notificaciones no contienen datos detallados de formularios ni respuestas. Después de recibir cada notificación, se requiere una llamada a la API independiente para recuperar datos actualizados. Consulta Uso sugerido para saber cómo hacerlo.

En el siguiente fragmento, se muestra una notificación de muestra para un cambio de esquema:

{
  "attributes": {
    "eventType": "SCHEMA",
    "formId": "18Xgmr4XQb-l0ypfCNGQoHAw2o82foMr8J0HPHdagS6g",
    "watchId": "892515d1-a902-444f-a2fe-42b718fe8159"
  },
  "messageId": "767437830649",
  "publishTime": "2021-03-31T01:34:08.053Z"
}

En el siguiente fragmento, se muestra una notificación de muestra para una respuesta nueva:

{
  "attributes": {
    "eventType": "RESPONSES",
    "formId": "18Xgmr4XQb-l0ypfCNGQoHAw2o82foMr8J0HPHdagS6g",
    "watchId": "5d7e5690-b1ff-41ce-8afb-b469912efd7d"
  },
  "messageId": "767467004397",
  "publishTime": "2021-03-31T01:43:57.285Z"
}

Configurar un tema de Cloud Pub/Sub

Las notificaciones se entregan a los temas de Cloud Pub/Sub. Desde Cloud Pub/Sub, puedes recibir notificaciones en un webhook o sondear un extremo de suscripción.

Para configurar un tema de Cloud Pub/Sub, haz lo siguiente:

  1. Completa los requisitos previos de Cloud Pub/Sub.
  2. Configura un cliente de Cloud Pub/Sub.
  3. Revisa los precios de Cloud Pub/Sub y habilita la facturación para tu proyecto de Developer Console.
  4. Crea un tema de Cloud Pub/Sub de una de las siguientes tres maneras:

  5. Crea una suscripción en Cloud Pub/Sub para indicarle a Cloud Pub/Sub cómo entregar tus notificaciones.

  6. Por último, antes de crear observadores que se dirijan a tu tema, debes otorgar permiso a la cuenta de servicio de las notificaciones de Formularios (forms-notifications@system.gserviceaccount.com) para que publique en tu tema.

Cómo crear un reloj

Una vez que tengas un tema al que pueda publicar la cuenta de servicio de las notificaciones push de la API de Forms, podrás crear notificaciones con el método watches.create(). Este método valida que la cuenta de servicio de notificaciones push pueda acceder al tema de Cloud Pub/Sub proporcionado y falla si no puede acceder al tema, por ejemplo, si el tema no existe o si no le otorgaste permiso de publicación en ese tema.

Python

forms/snippets/create_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
  creds = tools.run_flow(flow, store)

service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

watch = {
    "watch": {
        "target": {"topic": {"topicName": "<YOUR_TOPIC_PATH>"}},
        "eventType": "RESPONSES",
    }
}

form_id = "<YOUR_FORM_ID>"

# Print JSON response after form watch creation
result = service.forms().watches().create(formId=form_id, body=watch).execute()
print(result)

Node.js

forms/snippets/create_watch.js
import path from 'node:path';
import {authenticate} from '@google-cloud/local-auth';
import {forms} from '@googleapis/forms';

const formID = '<YOUR_FORM_ID>';

async function createWatch() {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });
  const watchRequest = {
    watch: {
      target: {
        topic: {
          topicName: 'projects/<YOUR_TOPIC_PATH>',
        },
      },
      eventType: 'RESPONSES',
    },
  };
  const result = await formsClient.forms.watches.create({
    formId: formID,
    requestBody: watchRequest,
  });
  console.log(result.data);
  return result.data;
}

Cómo borrar un reloj

Python

forms/snippets/delete_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"
watch_id = "<YOUR_WATCH_ID>"

# Print JSON response after deleting a form watch
result = (
    service.forms().watches().delete(formId=form_id, watchId=watch_id).execute()
)
print(result)

Node.js

forms/snippets/delete_watch.js
import path from 'node:path';
import {authenticate} from '@google-cloud/local-auth';
import {forms} from '@googleapis/forms';

const formID = '<YOUR_FORM_ID>';
const watchID = '<YOUR_FORMS_WATCH_ID>';

async function deleteWatch() {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });
  const result = await formsClient.forms.watches.delete({
    formId: formID,
    watchId: watchID,
  });
  console.log(result.data);
  return result.data;
}

Autorización

Al igual que todas las llamadas a la API de Forms, las llamadas a watches.create() deben autorizarse con un token de autorización. El token debe incluir un alcance que otorgue acceso de lectura a los datos sobre los que se envían las notificaciones.

Para que se entreguen las notificaciones, la aplicación debe conservar un otorgamiento de OAuth del usuario autorizado con los permisos requeridos. Si el usuario desconecta la aplicación, se detendrán las notificaciones y es posible que el reloj se suspenda con un error. Para reanudar las notificaciones después de recuperar la autorización, consulta Cómo renovar un reloj.

Enumera los relojes de un formulario

Python

forms/snippets/list_watches.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"

# Print JSON list of form watches
result = service.forms().watches().list(formId=form_id).execute()
print(result)

Node.js

forms/snippets/list_watches.js
import path from 'node:path';
import {authenticate} from '@google-cloud/local-auth';
import {forms} from '@googleapis/forms';

const formID = '<YOUR_FORM_ID>';

async function listWatches() {
  const auth = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/forms.responses.readonly',
  });
  const formsClient = forms({
    version: 'v1',
    auth,
  });
  const result = await formsClient.forms.watches.list({formId: formID});
  console.log(result.data);
  return result.data;
}

Cómo renovar un reloj

Python

forms/snippets/renew_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"
watch_id = "<YOUR_WATCH_ID>"

# Print JSON response after renewing a form watch
result = (
    service.forms().watches().renew(formId=form_id, watchId=watch_id).execute()
)
print(result)

Node.js

forms/snippets/renew_watch.js
import path from 'node:path';
import {authenticate} from '@google-cloud/local-auth';
import {forms} from '@googleapis/forms';

const formID = '<YOUR_FORM_ID>';
const watchID = '<YOUR_FORMS_WATCH_ID>';

async function renewWatch() {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });
  const result = await formsClient.forms.watches.renew({
    formId: formID,
    watchId: watchID,
  });
  console.log(result.data);
  return result.data;
}

Regulación

Las notificaciones se limitan: cada reloj puede recibir, como máximo, una notificación cada treinta segundos. Este umbral de frecuencia está sujeto a cambios.

Debido a la limitación, una sola notificación puede corresponder a varios eventos. En otras palabras, una notificación indica que se produjeron uno o más eventos desde la última notificación.

Límites

En cualquier momento, para un formulario y un tipo de evento determinados, cada proyecto de Cloud Console puede tener lo siguiente:

  • hasta 20 relojes en total
  • Hasta un reloj por usuario final

Además, en cualquier momento, cada formulario se limita a 50 observaciones por tipo de evento en total en todos los proyectos de Cloud Console.

Un reloj se asocia con un usuario final cuando se crea o renueva con las credenciales de ese usuario. Un reloj se suspende si el usuario final asociado pierde el acceso al formulario o revoca el acceso de la app al formulario.

Confiabilidad

Cada observación recibe una notificación al menos una vez después de cada evento, salvo en circunstancias extraordinarias. En la gran mayoría de los casos, las notificaciones se entregan minutos después de un evento.

Errores

Si las notificaciones para un reloj no se entregan de forma persistente, el estado del reloj se convierte en SUSPENDED y se configura el campo errorType del reloj. Para restablecer el estado de un reloj suspendido a ACTIVE y reanudar las notificaciones, consulta Renueva un reloj.

Uso sugerido

  • Usar un solo tema de Cloud Pub/Sub como destino de muchas observancias
  • Cuando se recibe una notificación sobre un tema, el ID del formulario se incluye en la carga útil de la notificación. Se usa con el tipo de evento para saber qué datos recuperar y de qué formulario recuperarlos.
  • Para recuperar los datos actualizados después de una notificación con EventType.RESPONSES, llama a forms.responses.list().
    • Establece el filtro en la solicitud como timestamp > timestamp_of_the_last_response_you_fetched.
  • Para recuperar los datos actualizados después de una notificación con EventType.SCHEMA, llama a forms.get().