Konfigurowanie i odbieranie powiadomień push

Za pomocą metod z kolekcji Watches możesz otrzymywać powiadomienia o zmianach danych w formularzach. Ta strona zawiera ogólny przegląd i instrukcje dotyczące konfigurowania i odbierania powiadomień push.

Przegląd

Funkcja powiadomień push w interfejsie Google Forms API umożliwia aplikacjom subskrybowanie powiadomień o zmianach danych w formularzach. Powiadomienia są dostarczane do tematu Cloud Pub/Sub zwykle w ciągu kilku minut od wprowadzenia zmiany.

Aby otrzymywać powiadomienia push, musisz skonfigurować temat Cloud Pub/Sub i podać jego nazwę podczas tworzenia obserwatora dla odpowiedniego typu zdarzenia.

Poniżej znajdziesz definicje najważniejszych pojęć używanych w tej dokumentacji:

  • Miejsce docelowe to miejsce, do którego są wysyłane powiadomienia. Jedynym obsługiwanym miejscem docelowym jest temat Cloud Pub/Sub.
  • Typ zdarzenia to kategoria powiadomień, które aplikacja firmy zewnętrznej może subskrybować.
  • Obserwator to instrukcja dla interfejsu Forms API, aby dostarczać powiadomienia o określonym typie zdarzenia w określonym formularzu do miejsca docelowego.

Gdy utworzysz obserwatora dla typu zdarzenia w określonym formularzu, miejsce docelowe tego obserwatora (czyli temat Cloud Pub/Sub) będzie otrzymywać powiadomienia o tych zdarzeniach w tym formularzu do momentu wygaśnięcia obserwatora. Obserwator działa przez tydzień, ale możesz go przedłużyć w dowolnym momencie przed wygaśnięciem, wysyłając żądanie do watches.renew().

Twój temat Cloud Pub/Sub będzie otrzymywać tylko powiadomienia o formularzach, które możesz wyświetlić za pomocą podanych przez siebie danych logowania. Jeśli na przykład użytkownik cofnie uprawnienia Twojej aplikacji lub utraci dostęp do edycji obserwowanego formularza, powiadomienia nie będą już dostarczane.

Dostępne typy zdarzeń

Interfejs Google Forms API oferuje obecnie 2 kategorie zdarzeń:

  • EventType.SCHEMA, który informuje o zmianach w treści i ustawieniach formularza.
  • EventType.RESPONSES, który informuje o przesłaniu odpowiedzi na formularz (zarówno nowych, jak i zaktualizowanych).

Odpowiedzi na powiadomienia

Powiadomienia są kodowane w formacie JSON i zawierają:

  • identyfikator formularza, który wywołał powiadomienie,
  • identyfikator obserwatora, który wywołał powiadomienie,
  • typ zdarzenia, które wywołało powiadomienie,
  • inne pola ustawione przez Cloud Pub/Sub, takie jak messageId i publishTime.

Powiadomienia nie zawierają szczegółowych danych formularza ani odpowiedzi. Po otrzymaniu każdego powiadomienia wymagane jest osobne wywołanie interfejsu API, aby pobrać aktualne dane. Informacje o tym, jak to zrobić, znajdziesz w sekcji Sugerowane użycie.

Ten fragment kodu przedstawia przykładowe powiadomienie o zmianie schematu:

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

Ten fragment kodu przedstawia przykładowe powiadomienie o nowej odpowiedzi:

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

Konfigurowanie tematu Cloud Pub/Sub

Powiadomienia są dostarczane do tematów Cloud Pub/Sub. Z Cloud Pub/Sub możesz otrzymywać powiadomienia za pomocą webhooka lub przez sondowanie punktu końcowego subskrypcji.

Aby skonfigurować temat Cloud Pub/Sub:

  1. Spełnij wymagania wstępne dotyczące Cloud Pub/Sub.
  2. Skonfiguruj klienta Cloud Pub/Sub.
  3. Zapoznaj się z cennikiem Cloud Pub/Sub, i włącz płatności w projekcie w konsoli Google Cloud.
  4. Utwórz temat Cloud Pub/Sub na jeden z 3 sposobów:

  5. Utwórz subskrypcję w Cloud Pub/Sub aby poinformować Cloud Pub/Sub, jak ma dostarczać powiadomienia.

  6. Na koniec, zanim utworzysz obserwatorów, którzy będą kierować powiadomienia do Twojego tematu, musisz przyznać uprawnienia do konta usługi powiadomień Formularzy (forms-notifications@system.gserviceaccount.com) do publikowania w tym temacie.

Tworzenie obserwatora

Gdy masz temat, w którym może publikować konto usługi powiadomień push interfejsu Forms API , możesz tworzyć powiadomienia za pomocą metody watches.create(). Ta metoda sprawdza, czy konto usługi powiadomień push może dotrzeć do podanego tematu Cloud Pub/Sub, i kończy się niepowodzeniem, jeśli nie może dotrzeć do tematu, np. jeśli temat nie istnieje lub nie przyznano mu uprawnień do publikowania w tym temacie.

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

Usuwanie obserwatora

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

Autoryzacja

Podobnie jak wszystkie wywołania interfejsu Forms API, wywołania watches.create() muszą być autoryzowane za pomocą tokena autoryzacji. Token musi zawierać zakres, który przyznaje dostęp do odczytu danych, o których są wysyłane powiadomienia.

Aby powiadomienia były dostarczane, aplikacja musi zachować uwierzytelnienie przez OAuth od autoryzowanego użytkownika z wymaganymi zakresami. Jeśli użytkownik odłączy aplikację, powiadomienia przestaną być wysyłane, a obserwator może zostać zawieszony z powodu błędu. Aby wznowić powiadomienia po odzyskaniu autoryzacji, przeczytaj sekcję Odnawianie obserwatora.

Wyświetlanie listy obserwatorów formularza

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

Odnawianie obserwatora

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

Ograniczenia

Powiadomienia są ograniczane – każdy obserwator może otrzymywać co najwyżej 1 powiadomienie co 30 sekund. Ten próg częstotliwości może ulec zmianie.

Ze względu na ograniczenia jedno powiadomienie może odpowiadać wielu zdarzeniom. Innymi słowy, powiadomienie wskazuje, że od ostatniego powiadomienia wystąpiło co najmniej 1 zdarzenie.

Limity

W dowolnym momencie w przypadku danego formularza i typu zdarzenia każdy projekt w Konsoli Cloud może mieć:

  • łącznie do 20 obserwatorów,
  • do 1 obserwatora na użytkownika.

Dodatkowo w dowolnym momencie każdy formularz jest ograniczony do 50 obserwatorów na typ zdarzenia we wszystkich projektach w Konsoli Cloud.

Obserwator jest powiązany z użytkownikiem, gdy jest tworzony lub odnawiany za pomocą danych logowania tego użytkownika. Obserwator jest zawieszany, jeśli powiązany z nim użytkownik utraci dostęp do formularza lub cofnie aplikacji dostęp do formularza.

Niezawodność

Każdy obserwator jest powiadamiany co najmniej raz po każdym zdarzeniu, z wyjątkiem wyjątkowych okoliczności. W zdecydowanej większości przypadków powiadomienie jest dostarczane w ciągu kilku minut od zdarzenia.

Błędy

Jeśli powiadomienia dla obserwatora nie są dostarczane, stan obserwatora zmienia się na SUSPENDED, a pole errorType obserwatora jest ustawione. Aby zresetować stan zawieszonego obserwatora na ACTIVE i wznowić powiadomienia, przeczytaj sekcję Odnawianie obserwatora.

Sugerowane użycie

  • Używaj jednego tematu Cloud Pub/Sub jako miejsca docelowego wielu obserwatorów.
  • Gdy otrzymasz powiadomienie w temacie, identyfikator formularza jest uwzględniany w ładunku powiadomienia. Użyj go z typem zdarzenia, aby wiedzieć, jakie dane pobrać i z którego formularza.
  • Aby pobrać zaktualizowane dane po otrzymaniu powiadomienia z EventType.RESPONSES, wywołaj forms.responses.list().
    • Ustaw filtr w żądaniu na timestamp > timestamp_of_the_last_response_you_fetched.
  • Aby pobrać zaktualizowane dane po otrzymaniu powiadomienia z EventType.SCHEMA, wywołaj forms.get().