Configura y recibe notificaciones push

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Puedes usar los métodos de la colección Watches para recibir notificaciones cuando los datos cambian en 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 Formularios de Google permite que las aplicaciones se suscriban a notificaciones cuando los datos cambian en los formularios. Las notificaciones se entregan a un tema de Cloud Pub/Sub, por lo general, unos minutos después del cambio.

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

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

  • Un objetivo es el lugar al que se envían las 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 puede suscribirse una aplicación de terceros.
  • Un reloj es una instrucción a la API de Formularios para entregar notificaciones sobre un tipo de evento específico en un formulario en particular a un destino.

Una vez que creas un reloj para un tipo de evento en un formulario en particular, el objetivo de ese reloj (que es un tema de Cloud Pub/Sub) recibe notificaciones de esos eventos en ese formulario hasta que el reloj venza. Tu 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 formularios que puedes ver con las credenciales que proporcionas. Por ejemplo, si el usuario revoca el permiso de la aplicación o pierde el acceso de edición a un formulario visto, las notificaciones ya no se entregan.

Tipos de eventos disponibles

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

  • EventType.SCHEMA, que notifica sobre las modificaciones en el contenido y la configuración de un formulario
  • EventType.RESPONSES, que notifica cuando se envían respuestas del formulario (nuevas y actualizadas)

Respuestas a notificaciones

Las notificaciones se codifican con JSON y contienen lo siguiente:

  • El ID del formulario de activación
  • El ID del reloj que lo activó
  • 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 sobre las respuestas ni los formularios. Después de recibir cada notificación, se requiere una llamada a la API diferente para recuperar datos actualizados. Consulta Uso recomendado para saber cómo lograrlo.

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 hook web o sondear un extremo de suscripción.

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

  1. Completa los requisitos 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. Puedes crear un tema de Cloud Pub/Sub de las siguientes tres maneras:

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

  6. Por último, antes de crear relojes orientados a tu tema, debes otorgar permiso a la cuenta de servicio de notificaciones de Formularios (forms-notifications@system.gserviceaccount.com) para publicar en tu tema.

Crear un reloj

Una vez que tengas un tema en el que la cuenta de servicio de notificaciones push de la API de Formularios pueda publicar, puedes 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 y falla si no puede llegar 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 __future__ import print_function

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

Formularios/fragmentos/create_watch.js
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';

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

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Cómo borrar un reloj

Python

forms/snippets/delete_watch.py.
from __future__ import print_function

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

formularios/snippets/delete_watch.js
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

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

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

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Autorización

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

Para que se entreguen las notificaciones, la aplicación debe retener una concesión de OAuth del usuario autorizado con los alcances requeridos. Si el usuario desconecta la aplicación, se detendrán las notificaciones y se suspenderá el reloj con un error. Para reanudar las notificaciones después de recuperar la autorización, consulta Renovar un reloj.

Enumerar los relojes de un formulario

Python

forms/snippets/list_watches.py.
from __future__ import print_function

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.
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';

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

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Renovar un reloj

Python

forms/snippets/renew_watch.py.
from __future__ import print_function

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
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

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

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

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Limitación

Se regulan las notificaciones: 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 tipo de evento y formulario determinados, cada proyecto de Cloud Console puede tener lo siguiente:

  • hasta veinte reproducciones en total
  • hasta un reloj por usuario final

Además, en cualquier momento, cada formulario se limita a 50 vistas 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 se 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 reloj recibe una notificación, al menos, una vez después de cada evento, en todas las circunstancias excepto en lo extraordinario. En la gran mayoría de los casos, la notificación se entrega en el transcurso de los minutos del evento.

Errores

Si las notificaciones de un reloj no se entregan de forma persistente, su estado pasa a ser SUSPENDED y se establece el campo errorType del reloj. Para restablecer el estado de un reloj suspendido a ACTIVE y reanudar las notificaciones, consulta Renovar un reloj.

Uso sugerido

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