Konfigurowanie i odbieranie powiadomień push

Aby otrzymywać powiadomienia o zmianach danych w formularzach, możesz użyć metod z kolecji Obserwuje. Ta strona zawiera ogólny opis i instrukcje konfigurowania oraz otrzymywania powiadomień push.

Omówienie

Funkcja powiadomień push interfejsu 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 obserwacji odpowiedniego typu zdarzenia.

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

  • Cel to miejsce, do którego wysyłane są powiadomienia. Jedynym obsługiwanym celem jest temat Cloud Pub/Sub.
  • Typ zdarzenia to kategoria powiadomień, do których aplikacja innej firmy może się zasubskrybować.
  • Obserwowanie to instrukcja dla interfejsu Forms API, aby wysyłać powiadomienia o określonym typie zdarzenia w określonym formularzu do celu.

Po utworzeniu monitorowania typu zdarzenia w konkretnym formularzu jego obiekt docelowy (czyli temat Cloud Pub/Sub) będzie otrzymywać powiadomienia z tych zdarzeń w tym formularzu do czasu wygaśnięcia monitorowania. Twoje zestawienie trwa tydzień, ale możesz je przedłużyć w dowolnym momencie przed jego wygaśnięciem, wysyłając żądanie watches.renew().

Temat Cloud Pub/Sub odbiera 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 formularza, powiadomienia nie będą już wysyłane.

Dostępne typy zdarzeń

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

  • EventType.SCHEMA, który powiadamia o zmianach w treści i ustawieniach formularza.
  • EventType.RESPONSES, który wysyła powiadomienia 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 wywołującego widoku
  • Typ zdarzenia, które spowodowało wysłanie powiadomienia
  • inne pola ustawione przez Cloud Pub/Sub, takie jak messageId i publishTime;

Powiadomienia nie zawierają szczegółowych danych z formularza ani odpowiedzi. Po otrzymaniu każdego powiadomienia wymagane jest osobne wywołanie interfejsu API w celu pobrania aktualnych danych. Więcej informacji na ten temat znajdziesz w sekcji Sugerowane sposoby korzystania z aplikacji.

Ten fragment kodu pokazuje 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 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ą web hooka lub przez odpytywanie punktu końcowego subskrypcji.

Aby skonfigurować temat Cloud Pub/Sub:

  1. Zapoznaj się z wymaganiami wstępnymi dotyczącymi Cloud Pub/Sub.
  2. Skonfiguruj klienta Cloud Pub/Sub.
  3. Zapoznaj się z cennikiem usługi Cloud Pub/Sub i włącz płatności w projekcie w konsoli dewelopera.
  4. Utwórz temat Cloud Pub/Sub w jeden z 3 sposobów:

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

  6. Na koniec, zanim utworzysz monitorowanie, które będzie kierować na Twój temat, musisz przyznać uprawnienia kontu usługi powiadomień w Formularzach (forms-notifications@system.gserviceaccount.com) do publikowania w Twoim temacie.

Tworzenie obserwacji

Gdy masz temat, który 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 uzyskać dostęp do podanego tematu w Cloud Pub/Sub. Jeśli nie może, metoda zakończy się niepowodzeniem. Może się tak zdarzyć, jeśli temat nie istnieje lub nie masz do niego uprawnień do publikowania.

PythonNode.js
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)
forms/snippets/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;

Usuwanie zegarka

PythonNode.js
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)
forms/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;

Autoryzacja

Podobnie jak w przypadku wszystkich wywołań interfejsu Forms API, wywołania interfejsu watches.create() muszą być autoryzowane za pomocą tokena autoryzacji. Token musi obejmować zakres, który przyznaje dostęp do odczytu danych o tym, które powiadomienia są wysyłane.

Aby powiadomienia były dostarczane, aplikacja musi zachować uprawnienia OAuth od autoryzowanego użytkownika z wymaganymi zakresami. Jeśli użytkownik odłączy aplikację, powiadomienia przestaną być wysyłane, a zegarek może zostać zawieszony z powodu błędu. Aby wznowić wysyłanie powiadomień po odzyskaniu autoryzacji, przeczytaj artykuł Odnawianie oglądania.

Wyświetlanie zegarków w formularzu

PythonNode.js
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)
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;

Odnawianie zegarka

PythonNode.js
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)
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;

Ograniczenia

Powiadomienia są ograniczane – każdy zegarek może otrzymać maksymalnie jedno powiadomienie co 30 sekund. Ten próg częstotliwości może ulec zmianie.

Z powodu ograniczania przepustowości pojedyncze 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 każdej chwili w każdym projekcie konsoli Cloud Console można mieć:

  • maksymalnie 20 oglądań
  • maksymalnie 1 zegarek na użytkownika.

Dodatkowo w każdej chwili każda forma jest ograniczona do 50 obserwacji na typ zdarzenia w całości w ramach wszystkich projektów w Cloud Console.

Po utworzeniu lub odnowieniu pliku z danymi logowania należącymi do użytkownika, jest on powiązany z tym użytkownikiem. Nadzór jest zawieszony, jeśli powiązany użytkownik utraci dostęp do formularza lub cofnie dostęp aplikacji do formularza.

Niezawodność

Każdy zegarek jest powiadamiany co najmniej raz po każdym zdarzeniu, z nielicznymi wyjątkami. W większości przypadków powiadomienie jest wysyłane w ciągu kilku minut od wystąpienia zdarzenia.

Błędy

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

Sugerowane zastosowanie

  • Używanie jednego tematu Cloud Pub/Sub jako miejsca docelowego wielu obserwacji.
  • Gdy otrzymasz powiadomienie na temat, identyfikator formularza jest dołączony do danych powiadomienia. Użyj go z typem zdarzenia, aby określić, jakie dane i z jakiego formularza pobrać.
  • Aby powiadomienie z EventType.RESPONSES pobierało zaktualizowane dane, wywołaj funkcję forms.responses.list().
    • Ustaw filtr żądania na timestamp > timestamp_of_the_last_response_you_fetched.
  • Aby pobrać zaktualizowane dane po powiadomieniu z EventType.SCHEMA, wywołaj funkcję forms.get().