Configurer et recevoir des notifications push

Vous pouvez utiliser les méthodes de la collection Watches pour recevoir des notifications lorsque des données sont modifiées dans des formulaires. Cette page fournit une présentation conceptuelle et des instructions pour configurer et recevoir des notifications push.

Présentation

La fonctionnalité de notifications push de l'API Google Forms permet aux applications de s'abonner aux notifications lorsque des données sont modifiées dans des formulaires. Les notifications sont envoyées à un sujet Cloud Pub/Sub, généralement quelques minutes après la modification.

Pour recevoir des notifications push, vous devez configurer un sujet Cloud Pub/Sub et fournir le nom de ce sujet lorsque vous créez une montre pour le type d'événement approprié.

Vous trouverez ci-dessous les définitions des concepts clés utilisés dans cette documentation :

  • Une cible est un emplacement où les notifications sont envoyées. La seule cible compatible est un sujet Cloud Pub/Sub.
  • Un type d'événement est une catégorie de notifications à laquelle une application tierce peut s'abonner.
  • Une surveillance est une instruction envoyée à l'API Forms pour qu'elle envoie des notifications pour un type d'événement particulier sur un formulaire spécifique à une cible.

Une fois que vous avez créé une montre pour un type d'événement sur un formulaire spécifique, la cible de cette montre (qui est un sujet Cloud Pub/Sub) reçoit des notifications de ces événements sur ce formulaire jusqu'à l'expiration de la montre. Votre montre dure une semaine, mais vous pouvez la prolonger à tout moment avant son expiration en envoyant une requête à watches.renew().

Votre sujet Cloud Pub/Sub ne reçoit que des notifications concernant les formulaires que vous pouvez consulter avec les identifiants que vous fournissez. Par exemple, si l'utilisateur révoque l'autorisation de votre application ou perd l'accès en modification à un formulaire surveillé, les notifications ne sont plus envoyées.

Types d'événements disponibles

L'API Google Forms propose actuellement deux catégories d'événements :

  • EventType.SCHEMA, qui envoie une notification lorsque le contenu et les paramètres d'un formulaire sont modifiés.
  • EventType.RESPONSES, qui envoie une notification lorsque des réponses à un formulaire (nouvelles et mises à jour) sont envoyées.

Réponses de notification

Les notifications sont encodées au format JSON et contiennent les éléments suivants :

  • L'ID du formulaire déclencheur
  • L'ID de la montre déclencheuse
  • Le type d'événement qui a déclenché la notification
  • D'autres champs définis par Cloud Pub/Sub, tels que messageId et publishTime

Les notifications ne contiennent pas de données détaillées sur le formulaire ni sur les réponses. Une fois chaque notification reçue, un appel d'API distinct est nécessaire pour récupérer les données actualisées. Pour savoir comment procéder, consultez Utilisation suggérée.

L'extrait de code suivant illustre un exemple de notification pour une modification de schéma :

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

L'extrait de code suivant illustre un exemple de notification pour une nouvelle réponse :

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

Configurer un sujet Cloud Pub/Sub

Les notifications sont envoyées aux sujets Cloud Pub/Sub. À partir de Cloud Pub/Sub, vous pouvez recevoir des notifications sur un webhook ou en interrogeant un point de terminaison d'abonnement.

Pour configurer un sujet Cloud Pub/Sub, procédez comme suit :

  1. Respectez les prérequis de Cloud Pub/Sub.
  2. Configurez un client Cloud Pub/Sub.
  3. Consultez les tarifs de Cloud Pub/Sub, et activez la facturation pour votre projet console Google Cloud.
  4. Créez un sujet Cloud Pub/Sub de l'une des trois manières suivantes :

  5. Créez un abonnement dans Cloud Pub/Sub pour indiquer à Cloud Pub/Sub comment envoyer vos notifications.

  6. Enfin, avant de créer des montres ciblant votre sujet, vous devez accorder l'autorisation au compte de service des notifications Forms (forms-notifications@system.gserviceaccount.com) de publier dans votre sujet.

Créer une montre

Une fois que vous disposez d'un sujet dans lequel le compte de service des notifications push de l'API Forms peut publier, vous pouvez créer des notifications à l'aide de la méthode watches.create(). Cette méthode vérifie que le compte de service des notifications push peut accéder au sujet Cloud Pub/Sub fourni. Si ce n'est pas le cas, elle échoue (par exemple, si le sujet n'existe pas ou si vous ne lui avez pas accordé l'autorisation de publication sur ce sujet).

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

// TODO: Replace with a valid form ID.
const formID = '<YOUR_FORM_ID>';

/**
 * Creates a watch on a form to get notifications for new responses.
 */
async function createWatch() {
  // Authenticate with Google and get an authorized client.
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });

  // Create a new Forms API client.
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });

  // The request body to create a watch.
  const watchRequest = {
    watch: {
      target: {
        topic: {
          // TODO: Replace with a valid Cloud Pub/Sub topic name.
          topicName: 'projects/<YOUR_TOPIC_PATH>',
        },
      },
      // The event type to watch for. 'RESPONSES' is the only supported type.
      eventType: 'RESPONSES',
    },
  };

  // Send the request to create the watch.
  const result = await formsClient.forms.watches.create({
    formId: formID,
    requestBody: watchRequest,
  });

  console.log(result.data);
  return result.data;
}

Supprimer une montre

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

// TODO: Replace with a valid form ID.
const formID = '<YOUR_FORM_ID>';
// TODO: Replace with a valid watch ID.
const watchID = '<YOUR_FORMS_WATCH_ID>';

/**
 * Deletes a watch from a form.
 */
async function deleteWatch() {
  // Authenticate with Google and get an authorized client.
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });

  // Create a new Forms API client.
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });

  // Send the request to delete the watch.
  const result = await formsClient.forms.watches.delete({
    formId: formID,
    watchId: watchID,
  });

  console.log(result.data);
  return result.data;
}

Autorisation

Comme tous les appels à l'API Forms, les appels à watches.create() doivent être autorisés avec un jeton d'autorisation. Le jeton doit inclure un champ d'application qui accorde un accès en lecture aux données sur lesquelles les notifications sont envoyées.

Pour que les notifications soient envoyées, l'application doit conserver une authentification OAuth de l'utilisateur autorisé avec les niveaux d'accès requis. Si l'utilisateur déconnecte l'application, les notifications cessent et la montre peut être suspendue avec une erreur. Pour reprendre les notifications après avoir récupéré l'autorisation, consultez Renouveler une montre.

Répertorier les montres d'un formulaire

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

// TODO: Replace with a valid form ID.
const formID = '<YOUR_FORM_ID>';

/**
 * Lists the watches for a given form.
 */
async function listWatches() {
  // Authenticate with Google and get an authorized client.
  const auth = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/forms.responses.readonly',
  });

  // Create a new Forms API client.
  const formsClient = forms({
    version: 'v1',
    auth,
  });

  // Get the list of watches for the form.
  const result = await formsClient.forms.watches.list({
    formId: formID,
  });

  console.log(result.data);
  return result.data;
}

Renouveler une montre

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

// TODO: Replace with a valid form ID.
const formID = '<YOUR_FORM_ID>';
// TODO: Replace with a valid watch ID.
const watchID = '<YOUR_FORMS_WATCH_ID>';

/**
 * Renews a watch on a form.
 */
async function renewWatch() {
  // Authenticate with Google and get an authorized client.
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });

  // Create a new Forms API client.
  const formsClient = forms({
    version: 'v1',
    auth: authClient,
  });

  // Send the request to renew the watch.
  const result = await formsClient.forms.watches.renew({
    formId: formID,
    watchId: watchID,
  });

  console.log(result.data);
  return result.data;
}

Limitations

Les notifications sont limitées : chaque montre ne peut recevoir qu'une seule notification toutes les 30 secondes. Ce seuil de fréquence est susceptible d'être modifié.

En raison de la limitation, une seule notification peut correspondre à plusieurs événements. En d'autres termes, une notification indique qu'un ou plusieurs événements se sont produits depuis la dernière notification.

Limites

À tout moment, pour un formulaire et un type d'événement donnés, chaque projet de console Cloud peut avoir :

  • jusqu'à 20 montres au total
  • jusqu'à une montre par utilisateur final

De plus, à tout moment, chaque formulaire est limité à 50 montres par type d'événement au total dans tous les projets de la console Cloud.

Une montre est associée à un utilisateur final lorsqu'elle est créée ou renouvelée avec les identifiants de cet utilisateur. Une montre est suspendue si l'utilisateur final associé perd l'accès au formulaire ou révoque l'accès de l'application au formulaire.

Fiabilité

Chaque montre est avertie au moins une fois après chaque événement, sauf dans des circonstances extraordinaires. Dans la grande majorité des cas, une notification est envoyée quelques minutes après un événement.

Erreurs

Si les notifications d'une montre ne sont pas envoyées de manière persistante, l'état de la montre devient SUSPENDED et le champ errorType de la montre est défini. Pour réinitialiser l'état d'une montre suspendue sur ACTIVE et reprendre les notifications, consultez Renouveler une montre.

Utilisation suggérée

  • Utilisez un seul sujet Cloud Pub/Sub comme cible de nombreuses montres.
  • Lorsque vous recevez une notification sur un sujet, l'ID du formulaire est inclus dans la charge utile de la notification. Utilisez-le avec le type d'événement pour savoir quelles données récupérer et dans quel formulaire.
  • Pour récupérer les données mises à jour après une notification avec EventType.RESPONSES, appelez forms.responses.list().
    • Définissez le filtre de la requête sur timestamp > timestamp_of_the_last_response_you_fetched.
  • Pour récupérer les données mises à jour après une notification avec EventType.SCHEMA, appelez forms.get().