Crea un comando iniziale

Questo documento spiega come creare un avviatore che consenta alla tua app o al tuo servizio di inviare una notifica a Google Workspace Studio quando si verifica un evento e avviare l'esecuzione di un flusso. Nell'API, gli starter sono chiamati workflowTriggers.

Un comando iniziale avvia un flusso, mentre un passaggio è una singola attività nella sequenza di attività che compongono un flusso. Creando un starter, consenti agli utenti di configurare flussi automatizzati che reagiscono a eventi in tempo reale dalla tua app o dal tuo servizio.

La creazione di un componente aggiuntivo iniziale prevede la dichiarazione del componente aggiuntivo iniziale nel file manifest del componente aggiuntivo e l'implementazione dei callback del ciclo di vita in Google Apps Script oppure l'attivazione del componente aggiuntivo iniziale pubblicando payload nell'endpoint API Google Workspace Studio.

Prerequisiti e autorizzazione OAuth

Per comunicare con l'endpoint API Workspace Studio, la tua app o il tuo servizio deve autenticarsi utilizzando OAuth 2.0. L'app deve richiedere il seguente ambito OAuth dedicato agli utenti durante l'autorizzazione:

https://www.googleapis.com/auth/workspace.studio.trigger

Questo ambito autorizza l'app a chiamare l'API Workspace Studio e a attivare i flussi che l'utente ha configurato per questo starter.

Accesso offline e token di aggiornamento

Poiché gli starter notificano a Workspace Studio in modo asincrono quando si verifica un evento nel servizio esterno, il che potrebbe accadere ore, giorni o mesi dopo che un utente ha configurato un flusso, il tuo servizio deve fornire un token di accesso OAuth 2.0 valido quando chiama l'endpoint API.

Il token di accesso fornito da Google nell'oggetto evento del componente aggiuntivo (ad esempio durante la configurazione iniziale o le richieste di callback del ciclo di vita) è di breve durata e valido solo per 1 ora. Non è sufficiente per attivare eventi di avvio in modo asincrono in futuro. Per chiamare l'API Workspace Studio nel tempo, il tuo servizio richiede un token di aggiornamento offline per generare token di accesso aggiornati su richiesta.

Il modo in cui gestisci l'autorizzazione e ottieni un token di aggiornamento dipende dal runtime del componente aggiuntivo:

  • Componenti aggiuntivi HTTP (runtime alternativi): per i componenti aggiuntivi HTTP, il servizio di backend deve implementare un flusso di autorizzazione OAuth 2.0 separato e indipendente dall'autorizzazione integrata del componente aggiuntivo per richiedere l'accesso offline (access_type=offline) e ricevere un token di aggiornamento.

    Puoi chiedere agli utenti di autorizzare questa connessione visualizzando una scheda di accesso o autorizzazione quando l'utente configura lo starter in Workspace Studio. Per saperne di più sulla restituzione delle schede di autorizzazione e sulla gestione del flusso OAuth, consulta Collegare il componente aggiuntivo di Google Workspace a un servizio di terze parti (trattando Google Workspace come il servizio di terze parti a cui ti connetti).

    Il servizio di backend deve archiviare il token di aggiornamento in modo sicuro (ad esempio, nel database del servizio insieme a triggerId) e utilizzarlo per recuperare un nuovo token di accesso ogni volta che si verifica un evento prima di inviare richieste all'endpoint API notifyUri o triggers.fire di starter.

  • Componenti aggiuntivi di Google Apps Script: i componenti aggiuntivi basati su Google Apps Script che utilizzano trigger pianificati (basati sul tempo) per eseguire il polling degli eventi possono saltare l'implementazione di un flusso OAuth indipendente. Poiché i trigger pianificati vengono eseguiti direttamente nell'ambiente di runtime di Google Apps Script, Google Apps Script gestisce e aggiorna automaticamente i token OAuth utilizzando gli ambiti dichiarati nel manifest.

Definisci lo starter nel file manifest

Per definire un comando iniziale, aggiungilo al file manifest dell'add-on (appsscript.json) all'interno del blocco addOns.studio.flows.workflowElements. Questa configurazione è necessaria sia per Apps Script sia per i runtime HTTP (runtime alternativi). Configura l'elemento come workflowTrigger anziché come workflowAction (utilizzato per definire un passaggio). Per saperne di più, vedi Struttura del file manifest per i componenti aggiuntivi Google Workspace.

All'interno del blocco workflowTrigger, specifica:

  • inputs: variabili configurate dall'utente nella scheda di configurazione (ad esempio nome del progetto, filtro delle risorse e così via).
  • outputs: Variabili restituibili dal punto di partenza ai passaggi successivi del flusso.
  • onConfigFunction: il nome della funzione di callback che mostra l'interfaccia di configurazione utente.
  • onManageFunction: il nome della funzione di callback richiamata da Google per gestire la creazione e l'eliminazione dell'abbonamento iniziale.

Il seguente esempio di codice mostra una definizione del manifest di esempio per un avviatore di eventi:

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Trigger App",
      "logoUrl": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/start/default/24px.svg",
      "useLocaleFromApp": true
    },
    "studio": {
      "flows": {
        "workflowElements": [
          {
            "id": "triggerDemo",
            "state": "ACTIVE",
            "name": "Event Trigger",
            "description": "Fires when a event occurs in the app.",
            "workflowTrigger": {
              "inputs": [
                {
                  "id": "projectId",
                  "description": "The project identifier to watch.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "outputs": [
                {
                  "id": "eventName",
                  "description": "The name of the triggered event.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                },
                {
                  "id": "eventMessage",
                  "description": "Detailed event message description.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "onConfigFunction": "onConfigTrigger",
              "onManageFunction": "onManageTrigger"
            }
          }
        ]
      }
    }
  }
}

Gestire il ciclo di vita dell'abbonamento iniziale

Quando un utente configura e attiva un flusso contenente il tuo starter o se il flusso è disattivato o eliminato, Google chiama il tuo componente aggiuntivo utilizzando la funzione di callback onManageFunction dichiarata nel manifest.

L'oggetto evento del ciclo di vita

La funzione di callback riceve un WorkflowEventObject contenente il contesto dell'azione. Per iniziare, sono inclusi:

  • Creazione trigger (event.workflow.triggerCreation): si attiva quando il flusso viene pubblicato o attivato.

    • triggerId: una stringa UUID univoca che identifica questa istanza di registrazione iniziale.

    • notifyUri: l'URL dell'endpoint API REST univoco associato a questa registrazione iniziale (ad esempio, https://workspacestudio.googleapis.com/v1/triggers/YOUR_TRIGGER_ID:fire).

    • inputs: gli input delle variabili configurati dall'utente dalla scheda.

  • Eliminazione attivatore (event.workflow.triggerDeletion): si attiva quando il comando iniziale viene rimosso dal flusso o quando l'intero flusso viene disattivato o eliminato.

    • triggerId: La stringa UUID univoca dell'istanza di abbonamento da liberare spazio.

Ciclo di vita dell'abbonamento di Alternate Runtimes (API HTTP)

Per i componenti aggiuntivi creati utilizzando runtime alternativi, le notifiche del ciclo di vita dell'abbonamento vengono inviate utilizzando richieste POST HTTP all'URL dell'endpoint HTTP configurato del componente aggiuntivo con il nome dell'azione specificato dalla funzione di callback onManageFunction. Il payload corrisponde alla rappresentazione JSON di WorkflowEventObject.

Per ulteriori informazioni sugli ambienti di runtime alternativi, vedi Creare un componente aggiuntivo di Google Workspace utilizzando endpoint HTTP.

Implementare i callback del ciclo di vita in Apps Script

Il seguente esempio di Apps Script mostra come configurare la scheda dell'interfaccia utente, gestire gli eventi del ciclo di vita dell'abbonamento utilizzando onManageTrigger e attivare la richiesta iniziale a Google quando si verifica un evento.

Apps Script

/**
 * Generates and returns the user configuration card to collect inputs.
 */
function onConfigTrigger() {
  const projectInput = CardService.newTextInput()
    .setFieldName("projectId")
    .setTitle("Project ID")
    .setHint("Enter the project identifier to watch");

  const section = CardService.newCardSection()
    .setHeader("Configure Event Trigger")
    .addWidget(projectInput);

  const card = CardService.newCardBuilder()
    .addSection(section)
    .build();

  return card;
}

/**
 * Handles subscription lifecycle events sent from Google Workspace Studio.
 *
 * @param {Object} event The Workspace Studio event object.
 */
function onManageTrigger(event) {
  const triggerCreation = event.workflow.triggerCreation;
  const triggerDeletion = event.workflow.triggerDeletion;

  if (triggerCreation) {
    const triggerId = triggerCreation.triggerId;
    const notifyUri = triggerCreation.notifyUri;
    const inputs = triggerCreation.inputs;

    // Extract input values configured by the user.
    const projectId = inputs["projectId"].stringValues[0];

    // TODO: Save triggerId, notifyUri, and projectId in your database/service.
    // Your backend service listens for events related to 'projectId'
    // and calls notifyUri when those events occur.
    console.log("Trigger subscription created: " + triggerId +
                ", Notify URI: " + notifyUri +
                ", Match Project: " + projectId);

  } else if (triggerDeletion) {
    const triggerId = triggerDeletion.triggerId;

    // TODO: Remove references to triggerId from your database and stop
    // sending future event notifications to the associated notifyUri.
    console.log("Trigger subscription deleted: " + triggerId);
  }
}

/**
 * Mock function showing how your backend service fires the trigger.
 * This logic runs on your service when a watched event occurs.
 *
 * @param {string} notifyUri The stored notifyUri associated with the trigger.
 * @param {string} triggerId The stored triggerId.
 * @param {string} userAccessToken The OAuth 2.0 access token for the user
 *     (obtained using your stored refresh token).
 */
function simulateEventFire(notifyUri, triggerId, userAccessToken) {
  // A unique UUID version 4 is recommended as the requestId for idempotency.
  const requestId = Utilities.getUuid();

  const payload = {
    "name": "triggers/" + triggerId,
    "outputs": {
      "eventName": { "stringValues": ["EventOccurred"] },
      "eventMessage": { "stringValues": ["Hello from the service!"] }
    },
    "requestId": requestId
  };

  const options = {
    "method": "POST",
    "contentType": "application/json",
    "headers": {
      "Authorization": "Bearer " + userAccessToken
    },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true
  };

  const response = UrlFetchApp.fetch(notifyUri, options);
  const responseCode = response.getResponseCode();

  if (responseCode === 200) {
    console.log("Trigger successfully fired!");
  } else if (responseCode === 404) {
    // 404 means the trigger registration is invalid or deleted.
    console.log("Trigger not found. Stop sending events for this trigger.");
    // TODO: Clean up the trigger from your backend database.
  } else if (responseCode === 429 || responseCode >= 500) {
    console.log("Temporary error (" + responseCode + "). Retry using exponential backoff.");
  } else {
    console.log("Failed to fire trigger. HTTP Code: " + responseCode + " - " + response.getContentText());
  }
}

Utilizzare l'API Workspace Studio

Puoi utilizzare l'API Workspace Studio (workspacestudio.googleapis.com) per comunicare in modo programmatico a Google gli eventi iniziali.

Gli endpoint si trovano nel percorso di base: https://workspacestudio.googleapis.com/v1.

Notifica un evento iniziale

Attiva un avviatore utilizzando il metodo triggers.fire per avviare l'esecuzione di un flusso.

  • Metodo HTTP: POST
  • Percorso: /v1/triggers/{triggerId}:fire (dove {triggerId} è l'identificatore univoco recuperato durante la creazione dell'abbonamento al trigger)
  • Ambito OAuth: https://www.googleapis.com/auth/workspace.studio.trigger

Il seguente esempio di codice mostra come attivare un comando iniziale nella richiesta.

Richiesta

{
  "name": "triggers/TRIGGER_ID",
  "outputs": {
    "eventName": {
      "stringValues": [
        "EventOccurred"
      ]
    },
    "eventMessage": {
      "stringValues": [
        "Hello from the service!"
      ]
    }
  },
  "log": {
    "textFormatElements": [
      {
        "text": "An event occurred in the app."
      }
    ]
  },
  "requestId": "UNIQUE_REQUEST_ID"
}
  • name (stringa, obbligatorio): il nome della risorsa di avvio, formattato come triggers/{triggerId}.
  • outputs (mappa, facoltativo): una mappa delle variabili di output del comando iniziale che rappresentano i dati sugli eventi. Ogni valore è un oggetto VariableData che supporta elenchi digitati (ad esempio, stringValues, booleanValues, integerValues).
  • log (oggetto, facoltativo): una rappresentazione del markup TextFormat mostrata nei log dell'attività di esecuzione di Workspace Studio.
  • requestId (stringa, facoltativo): un identificatore univoco (consigliato UUID v4) di un massimo di 36 caratteri ASCII per garantire l'idempotenza dell'API in caso di nuovi tentativi.

Risposta

In caso di esito positivo, la risposta restituisce un oggetto JSON vuoto {}.

Quote API Workspace Studio

Il traffico inviato al servizio workspacestudio.googleapis.com è limitato per evitare il sovraccarico del sistema, incoraggiare l'utilizzo corretto delle risorse e proteggere le prestazioni complessive di Google Workspace.

Vengono applicate le seguenti quote:

Tipo di quota Quota
Al minuto per progetto 1000 richieste iniziali
Al minuto per utente 100 richieste iniziali

I tipi di quota sono:

  • Al minuto per progetto: limita il numero cumulativo di eventi iniziali attivati da un singolo progetto Google Cloud dello sviluppatore a 1000 richieste al minuto per tutti gli utenti che eseguono i relativi starter.
  • Al minuto per utente: limita a 100 richieste al minuto le invocazioni cumulative di starter di un singolo utente finale in un determinato progetto Cloud.

Gestire gli errori di quota basati sul tempo

Se superi queste quote, l'API restituisce un codice di errore HTTP 429 Too Many Requests (o 429 Resource Exhausted) che indica che la quota di frequenza è stata superata.

Per risolvere questi errori, il codice deve rilevare l'eccezione e utilizzare una strategia di backoff esponenziale troncato. Il backoff esponenziale ritenta le richieste non riuscite utilizzando ritardi progressivamente più lunghi tra i tentativi, incluso il jitter casuale (ricalcolando un ritardo casuale a ogni iterazione) per impedire a più client di sincronizzarsi e riprovare contemporaneamente:

  1. Invia una richiesta all'API Workspace Studio.
  2. Se la richiesta non va a buon fine e viene visualizzato un errore 429, attendi 1 second + random_number_milliseconds e riprova.
  3. Se l'operazione non riesce di nuovo, attendi 2 seconds + random_number_milliseconds e riprova.
  4. Se l'operazione non riesce di nuovo, attendi 4 seconds + random_number_milliseconds e riprova.
  5. Continua questo ciclo, raddoppiando il ritardo fino a una soglia di maximum_backoff (in genere 32 o 64 secondi).
  6. Una volta raggiunta la durata massima di backoff, riprova utilizzando quel ritardo costante finché non viene raggiunto il limite massimo di tentativi, quindi interrompi e registra l'errore.

Best practice

Quando progetti e implementi un avviatore, tieni presente le seguenti best practice:

Emetti singoli eventi anziché elenchi batch

Progetta il comando iniziale in modo che generi un singolo evento per ogni occorrenza distinta (ad esempio un singolo record aggiornato, un nuovo messaggio pubblicato o un'attività assegnata) anziché generare un singolo evento contenente un batch o un elenco di elementi:

  • Coerenza con gli starter integrati: in Workspace Studio, gli starter Google Workspace integrati (ad esempio la ricezione di un'email in Gmail o l'ingresso di un utente in uno spazio di Google Chat) vengono attivati da un singolo evento. L'emissione di eventi a un solo elemento è in linea con questo comportamento e offre un'esperienza coerente e prevedibile per gli utenti di tutti gli starter.
  • Configurazione più semplice del flusso: i passaggi successivi in un flusso in genere elaborano un elemento alla volta. L'emissione di eventi a un solo elemento consente agli utenti di mappare le variabili direttamente senza aggiungere passaggi complessi per scorrere gli array o analizzare gli elenchi.
  • Gestisci singolarmente il polling e le modifiche batch: se il tuo servizio di backend esegue il polling di un'API esterna e rileva più elementi modificati durante un singolo intervallo di polling, attiva un evento iniziale individuale per ogni elemento anziché raggrupparli in un unico evento batch.
  • Gestisci la frequenza degli eventi e le quote: poiché l'attivazione di singoli eventi per più elementi modificati può causare un'improvvisa raffica di richieste, assicurati che il tuo servizio rispetti le quote dell'API Workspace Studio (ad esempio il limite di 100 richieste al minuto per utente). Se un ciclo di polling produce un volume elevato di elementi (ad esempio, più di 100 record modificati), distribuisci gli eventi nel tempo per evitare errori 429 Too Many Requests.

Comportamenti principali e casi limite

Quando integrano gli starter, gli sviluppatori devono gestire comportamenti di errore specifici e funzionalità di runtime:

  • Nessun supporto per le prove: Workspace Studio non supporta le prove per i principianti.
  • Idempotenza e prevenzione della riproduzione: anche se non strettamente necessario, devi includere un requestId univoco (ad esempio un UUID) nel payload HTTP o Apps Script. Fornire un requestId garantisce l'idempotenza consentendo all'API di rilevare e ignorare le notifiche duplicate, impedendo l'esecuzione del flusso più volte per un singolo evento.
  • Flussi disattivati e riattivati: quando un flusso contenente il tuo starter viene disattivato in Workspace Studio, Google invia un evento del ciclo di vita triggerDeletion al tuo callback onManageFunction. Inoltre, tutte le chiamate al metodo FireTrigger associato restituiscono un codice di ritorno di errore 404 Not Found (Requested entity was not found.). Il tuo servizio deve reagire agli errori 404 interrompendo le future notifiche di eventi per l'ID istanza di avvio.

    Se un utente riattiva in un secondo momento il flusso, Google avvia un nuovo ciclo di vita dell'abbonamento richiamando il callback onManageFunction con un nuovo evento triggerCreation contenente un nuovo triggerId e notifyUri. Il precedente triggerId è stato ritirato definitivamente e non viene riattivato, pertanto il servizio non deve eseguire il polling o controllare se una vecchia istanza di trigger è stata riattivata. Per maggiori informazioni, consulta la sezione Gestire il ciclo di vita dell'abbonamento iniziale.

  • Eliminazione idempotente dell'abbonamento: la funzione di callback onManageFunction deve gestire le richieste di eliminazione dell'abbonamento da parte di Google in modo idempotente. Se Google chiama più volte l'hook di eliminazione per lo stesso triggerId (ad esempio, durante i tentativi dovuti a perdite di connessione temporanee), la funzione deve essere restituita correttamente.

  • Quote dei flussi: oltre alle quote dell'API Workspace Studio, i flussi degli utenti sono soggetti a controlli interni aggiuntivi delle quote. I loop ad alta frequenza o un volume eccessivo di eventi potrebbero superare le soglie di sicurezza, causando la disattivazione automatica del flusso.