Konfigurowanie i odbieranie powiadomień push

Możesz używać metod z kolekcji Watches, aby otrzymywać powiadomienia o zmianach danych w formularzach. Na tej stronie znajdziesz ogólne omówienie i instrukcje konfigurowania oraz otrzymywania 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 obserwowania odpowiedniego typu zdarzenia.

Poniżej znajdziesz definicje kluczowych 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ń, do których może subskrybować aplikacja firmy zewnętrznej.
  • Obserwowanie to instrukcja dla interfejsu Forms API, aby dostarczać powiadomienia o określonym typie zdarzenia w określonym formularzu do miejsca docelowego.

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

Temat Cloud Pub/Sub otrzymuje 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 aplikacji lub utraci dostęp do edycji obserwowanego formularza, powiadomienia nie będą już dostarczane.

Dostępne typy zdarzeń

Interfejs Google Forms API udostępnia obecnie 2 kategorie zdarzeń:

  • EventType.SCHEMA, które powiadamia o zmianach w treści i ustawieniach formularza.
  • EventType.RESPONSES, która powiadamia 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ł działanie
  • Identyfikator zegarka, który wywołał działanie
  • Typ zdarzenia, które spowodowało wysłanie powiadomienia.
  • Inne pola ustawione przez Cloud Pub/Sub, np. messageIdpublishTime

Powiadomienia nie zawierają szczegółowych danych formularza ani odpowiedzi. Po otrzymaniu każdego powiadomienia musisz wykonać osobne wywołanie interfejsu API, aby pobrać nowe dane. Więcej informacji znajdziesz w sekcji Sugerowane użycie.

Poniższy 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"
}

Poniższy fragment kodu pokazuje 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ą wywołania zwrotnego 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 za projekt w Konsoli dewelopera.
  4. Utwórz temat Cloud Pub/Sub na jeden z 3 sposobów:

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

  6. Zanim utworzysz obserwacje kierowane na Twój temat, musisz przyznać uprawnienia kontu usługi powiadomień Formularzy (forms-notifications@system.gserviceaccount.com) do publikowania w Twoim temacie.

Tworzenie zegarka

Gdy masz już temat, do którego konto usługi powiadomień push interfejsu Forms API może publikować informacje, możesz tworzyć powiadomienia za pomocą metody watches.create(). Ta metoda sprawdza, czy konto usługi powiadomień push może uzyskać dostęp do podanego tematu Cloud Pub/Sub. Jeśli nie może, np. gdy temat nie istnieje lub nie masz uprawnień do publikowania w tym temacie, metoda zwraca błąd.

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 zegarka

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, na podstawie których wysyłane są powiadomienia.

Aby powiadomienia były dostarczane, aplikacja musi zachować przyznane przez autoryzowanego użytkownika uprawnienia OAuth z wymaganymi zakresami. Jeśli użytkownik odłączy aplikację, powiadomienia przestaną być wysyłane, a zegarek może zostać zawieszony z błędem. Aby wznowić powiadomienia po ponownym uzyskaniu autoryzacji, przeczytaj artykuł Odnowienie zegarka.

Wyświetlanie zegarków w formularzu

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

Odnowienie zegarka

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 zegarek może otrzymywać maksymalnie 1 powiadomienie co 30 sekund. Ten próg częstotliwości może ulec zmianie.

Ze względu na ograniczanie liczby powiadomień jedno powiadomienie może odpowiadać wielu zdarzeniom. Inaczej mówiąc, 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 konsoli Cloud może mieć:

  • do 20 obejrzeń
  • maksymalnie 1 zegarek na użytkownika;

Dodatkowo w każdym momencie każdy formularz jest ograniczony do 50 obserwacji na typ zdarzenia we wszystkich projektach Cloud Console.

Zegarek jest powiązany z użytkownikiem końcowym, gdy jest tworzony lub odnawiany przy użyciu danych logowania tego użytkownika. Zegarek jest zawieszony, jeśli powiązany użytkownik końcowy utraci dostęp do formularza lub cofnie dostęp aplikacji do formularza.

Niezawodność

Każdy zegarek jest powiadamiany co najmniej raz po każdym wydarzeniu, z wyjątkiem sytuacji nadzwyczajnych. W większości przypadków powiadomienie jest dostarczane w ciągu kilku minut od zdarzenia.

Błędy

Jeśli powiadomienia na zegarek nie są dostarczane, stan zegarka zmienia się na SUSPENDED, a pole errorType zegarka jest ustawione. Aby zresetować stan zawieszonego zegarka do ACTIVE i wznowić powiadomienia, przeczytaj artykuł Odnawianie zegarka.

Sugerowane zastosowanie

  • Używaj jednego tematu Cloud Pub/Sub jako miejsca docelowego wielu obserwacji.
  • Gdy otrzymasz powiadomienie na dany temat, identyfikator formularza zostanie uwzględniony w ładunku powiadomienia. Używaj go z typem zdarzenia, aby wiedzieć, jakie dane pobrać i z jakiego formularza.
  • Aby pobrać zaktualizowane dane po otrzymaniu powiadomienia z EventType.RESPONSES, wywołaj funkcję 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 funkcję forms.get().