Integrando Google Forms com Google Cloud Pub/Sub e App Integration via Apps Script: Um Guia Detalhado
This article is also available in English here.
Nesse artigo, vou falar muito pouco sobre Application Integration! Basta saber que o objetivo aqui é disparar uma integração no App Integration quando um Google Form é submetido (pegando, claro, o conteúdo do Forms como input para a integração). A ponte aqui será feita via Pub/Sub. Ou seja, o objetivo é entregar o conteúdo do Form submetido num Pub/Sub. Isso feito, basta criar uma integração que usa o PubSub Trigger
Vamos lá!
O Google Forms é uma ferramenta fantástica para coletar dados, mas e se você precisar processar essas respostas em tempo real ou integrá-las com sistemas backend mais complexos? Uma solução poderosa é enviar os dados de cada resposta para um tópico do Google Cloud Pub/Sub assim que o formulário for enviado. Isso abre portas para processamento de dados em tempo real, análise, acionando o App Integration e muito mais.
Neste post, vamos detalhar como configurar um script no Google Apps Script para publicar automaticamente os dados de um Google Form em um tópico Pub/Sub, com foco especial nos detalhes de permissão e configuração do ambiente.
Pré-requisitos:
- Conta Google: Necessária para criar o Google Form e o projeto no Google Cloud.
- Projeto Google Cloud Platform (GCP): Um projeto ativo onde você criará o tópico Pub/Sub e habilitará as APIs necessárias.
- Google Form: O formulário que você deseja integrar.
Passo 1: Configuração do Projeto Google Cloud (GCP)
Antes de mexer no script, precisamos preparar o ambiente no GCP.
- Selecione ou Crie um Projeto GCP: Acesse o Google Cloud Console e selecione o projeto que deseja usar ou crie um novo. Anote o ID do Projeto (Project ID), pois você precisará dele no script.
- Habilite a API Pub/Sub, Google Forms e AppsScript:
- No menu de navegação, vá para “APIs & Services” → “Library”.
- Procure por “Cloud Pub/Sub API” e clique em “Enable”. Se já estiver habilitada, ótimo. Faça o mesmo para Google Forms e AppsScript.
- Crie um Tópico Pub/Sub:
- No menu de navegação, vá para “Pub/Sub” → “Topics”.
- Clique em “Create Topic”.
- Dê um nome ao seu tópico (por exemplo,
form-submission
). Anote esse Nome do Tópico (Topic ID). - Mantenha as outras configurações padrão por enquanto e clique em “Create”.
Passo 2: Configuração do Google Apps Script
Agora, vamos conectar nosso Google Form ao script e ao nosso projeto GCP.
- Abra o Editor de Scripts: Abra seu Google Form, clique nos três pontos verticais (Mais) no canto superior direito e selecione “Script editor”.
- Associe o Script ao Projeto GCP: Este é um passo crucial para que o script possa usar os serviços do GCP e obter o token de autenticação correto.
- No editor de scripts, clique no ícone de engrenagem (“Project Settings”) na barra lateral esquerda.
- Marque a caixa “Show “appsscript.json” manifest file in editor”.
- Role para baixo até a seção “Google Cloud Platform (GCP) Project”.
- Clique em “Change Project”.
- Cole o Número do Projeto GCP (GCP Project Number - você pode encontrá-lo na página inicial do seu projeto no Cloud Console, geralmente abaixo do ID do Projeto) e clique em “Set Project”.
- Confirme a alteração. Isso garante que o
ScriptApp.getOAuthToken()
solicitará um token com permissão para interagir com o seu projeto GCP configurado.
Passo 3: O Código Apps Script
Copie e cole o seguinte código no editor de scripts (geralmente no arquivo Code.gs
).
JavaScript
/**
* Configuração: Substitua pelos seus valores!
*/
const GcpProjectId = 'SEU_GCP_PROJECT_ID'; // <-- Substitua pelo ID do seu projeto GCP
const PubSubTopicName = 'SEU_PUBSUB_TOPIC_ID'; // <-- Substitua pelo ID do seu tópico Pub/Sub
/**
* Esta função é acionada quando um formulário é enviado.
* @param {GoogleAppsScript.Events.FormsOnSubmit} e O objeto de evento da submissão do formulário.
*/
function onFormSubmit(e) {
try {
// Obtém a resposta do formulário do objeto de evento
const formResponse = e.response;
if (!formResponse) {
Logger.log('Objeto de evento não contém uma resposta de formulário.');
return;
}
// Obtém todas as respostas aos itens da submissão
const itemResponses = formResponse.getItemResponses();
// Cria um objeto de dados para armazenar os valores do formulário
const formData = {
timestamp: formResponse.getTimestamp().toISOString(), // Data/hora da submissão em formato ISO
respondentEmail: formResponse.getRespondentEmail() || 'anonymous', // Email do respondente (se coletado e permitido)
responses: {} // Objeto para mapear perguntas e respostas
};
// Mapeia as perguntas do formulário para as respostas
itemResponses.forEach(itemResponse => {
const question = itemResponse.getItem().getTitle(); // Obtém o texto da pergunta
const answer = itemResponse.getResponse(); // Obtém a resposta
formData.responses[question] = answer; // Adiciona ao objeto de respostas
});
// Envia para o Pub/Sub usando chamada HTTP direta com token OAuth
const result = publishToPubSub(formData);
Logger.log('Mensagem publicada no Pub/Sub: ' + result);
} catch (error) {
// Registra qualquer erro que ocorra durante o processo
Logger.log('Erro em onFormSubmit: ' + error.toString() + '\nStack: ' + error.stack);
}
}
/**
* Publica uma mensagem no Pub/Sub usando o token OAuth do Apps Script.
* @param {Object} data O objeto de dados a ser publicado.
* @return {string} O corpo da resposta da API Pub/Sub em caso de sucesso.
* @throws {Error} Se a publicação falhar.
*/
function publishToPubSub(data) {
// Validação básica das constantes
if (!GcpProjectId || GcpProjectId === 'SEU_GCP_PROJECT_ID') {
throw new Error('GcpProjectId não está configurado. Edite o script e substitua o placeholder.');
}
if (!PubSubTopicName || PubSubTopicName === 'SEU_PUBSUB_TOPIC_ID') {
throw new Error('PubSubTopicName não está configurado. Edite o script e substitua o placeholder.');
}
// Prepara a mensagem para a API Pub/Sub
const pubsubData = {
messages: [
{
// Os dados precisam ser codificados em Base64
data: Utilities.base64Encode(JSON.stringify(data))
}
]
};
// Obtém o token OAuth do ambiente Apps Script.
// ISSO É CRUCIAL: O token pertence ao USUÁRIO que autoriza o script.
// Este usuário DEVE ter permissão para publicar no tópico Pub/Sub
// especificado no projeto GCP associado ao script.
// A permissão necessária no IAM é, tipicamente, 'roles/pubsub.publisher'.
const token = ScriptApp.getOAuthToken();
// Monta a URL do endpoint da API Pub/Sub
const pubsubUrl = `https://pubsub.googleapis.com/v1/projects/${GcpProjectId}/topics/${PubSubTopicName}:publish`;
// Configura as opções da requisição HTTP
const options = {
method: 'post', // Método HTTP POST
contentType: 'application/json', // Tipo de conteúdo do payload
// O payload deve ser uma string JSON
payload: JSON.stringify(pubsubData),
headers: {
// Autenticação usando o token OAuth obtido
Authorization: 'Bearer ' + token
},
muteHttpExceptions: true // Importante: Captura erros HTTP para tratamento manual
};
// Faz a chamada para a API Pub/Sub usando UrlFetchApp
const response = UrlFetchApp.fetch(pubsubUrl, options);
// Verifica o código de status da resposta HTTP
const responseCode = response.getResponseCode();
const responseText = response.getContentText();
// Se a resposta for bem-sucedida (códigos 2xx)
if (responseCode >= 200 && responseCode < 300) {
Logger.log('Resposta da API Pub/Sub (Sucesso): ' + responseText);
return responseText; // Retorna o corpo da resposta (geralmente contém os messageIds)
} else {
// Se houver erro, loga detalhes e lança uma exceção
Logger.log(`Erro ao publicar no Pub/Sub. Código: ${responseCode}. Resposta: ${responseText}`);
throw new Error(`Falha ao publicar no Pub/Sub: ${responseText} (Código: ${responseCode})`);
}
}
/**
* Configura o gatilho (trigger) 'onFormSubmit' para o formulário ativo.
* Esta função deve ser executada manualmente UMA VEZ pelo editor de scripts.
*/
function createFormSubmitTrigger() {
// Remove gatilhos antigos para evitar duplicatas (opcional, mas recomendado)
const currentTriggers = ScriptApp.getProjectTriggers();
currentTriggers.forEach(trigger => {
if (trigger.getHandlerFunction() === 'onFormSubmit' &&
trigger.getEventType() === ScriptApp.EventType.ON_FORM_SUBMIT) {
ScriptApp.deleteTrigger(trigger);
Logger.log('Gatilho onFormSubmit existente removido.');
}
});
// Obtém o formulário ao qual o script está vinculado
const form = FormApp.getActiveForm();
// Cria um novo gatilho que chama 'onFormSubmit' quando o formulário é enviado
ScriptApp.newTrigger('onFormSubmit')
.forForm(form)
.onFormSubmit()
.create();
Logger.log('Gatilho onFormSubmit criado com sucesso.');
}
Explicação Detalhada do Código:
- Constantes Globais (
GcpProjectId
,PubSubTopicName
É essencial que você substitua os valores placeholder
'SEU_GCP_PROJECT_ID'
e'SEU_PUBSUB_TOPIC_ID'
pelos seus IDs reais obtidos no Passo 1. onFormSubmit(e)
:- Esta função é o gatilho (trigger). Ela é automaticamente executada pelo Google Apps Script sempre que o formulário vinculado recebe uma nova resposta.
e
: O objeto de evento que contém informações sobre a submissão, incluindo ae.response
.formResponse.getItemResponses()
: Obtém um array com cada pergunta e sua respectiva resposta.formData
: Criamos um objeto JSON estruturado para enviar ao Pub/Sub. Inclui:timestamp
: Data e hora da submissão em formato padronizado ISO 8601.respondentEmail
: O email do usuário que respondeu (se a coleta de email estiver habilitada no formulário e o usuário permitir). Caso contrário, ‘anonymous’.responses
: Um objeto onde cada chave é o título da pergunta e o valor é a resposta dada.
- O loop
forEach
itera sobre as respostas, extraindo o título da pergunta (item.getTitle()
) e a resposta (itemResponse.getResponse()
) e populando o objetoformData.responses
. - Chama a função
publishToPubSub
para enviar os dados coletados. try...catch
: Captura e loga quaisquer erros que possam ocorrer durante o processamento da resposta.
publishToPubSub(data)
:- Esta função é responsável pela comunicação direta com a API do Pub/Sub.
- Prepara o payload (
pubsubData
) no formato esperado pela API Pub/Sub: um objeto com uma chavemessages
, que é um array contendo objetos de mensagem. Cada mensagem tem uma chavedata
cujo valor deve ser o payload real codificado em Base64. UsamosUtilities.base64Encode(JSON.stringify(data))
para isso. ScriptApp.getOAuthToken()
: Este é o ponto chave da autenticação. Ele retorna um token OAuth 2.0 que representa o usuário que autorizou o script. Quando você (ou quem configurar o gatilho) executarcreateFormSubmitTrigger
pela primeira vez, o Google solicitará permissão para o script acessar serviços externos (como o Pub/Sub) em nome desse usuário. Portanto, o usuário que autoriza o script DEVE ter as permissões IAM necessárias no projeto GCP associado para publicar mensagens no tópico Pub/Sub especificado (normalmente, o papelroles/pubsub.publisher
ou um papel mais amplo que o inclua, comoroles/editor
ouroles/owner
).UrlFetchApp.fetch()
: Faz a requisição HTTP POST para o endpoint da API Pub/Sub.- A URL é construída usando seu
GcpProjectId
ePubSubTopicName
. headers
: Inclui o cabeçalhoAuthorization: Bearer <token>
para autenticar a chamada usando o token obtido.payload
: O JSON da mensagem Pub/Sub.muteHttpExceptions: true
: Impede que erros HTTP (como 403 Forbidden, 404 Not Found) parem a execução do script imediatamente. Isso nos permite verificarresponse.getResponseCode()
manualmente.
- A URL é construída usando seu
- Verificação da Resposta: Checa se o código de status HTTP (
responseCode
) está na faixa de sucesso (200-299). Se sim, loga e retorna a resposta da API. Se não, loga o erro e lança uma exceção para indicar a falha, que será capturada pelotry...catch
emonFormSubmit
.
createFormSubmitTrigger()
:- Esta função é auxiliar e precisa ser executada manualmente UMA VEZ a partir do editor de scripts.
- Ela primeiro remove gatilhos
onFormSubmit
antigos para evitar execuções duplicadas caso você a execute mais de uma vez. - Em seguida, ela cria programaticamente o gatilho (trigger) que vincula o evento
onFormSubmit
do formulário ativo à execução da funçãoonFormSubmit
no seu script. - Ao executar esta função pela primeira vez, o Google solicitará as autorizações necessárias.
Passo 4: Autorização e Teste
- Salve o Script: Clique no ícone de disquete (“Save project”).
- Execute
createFormSubmitTrigger
:- No menu suspenso acima do código (onde provavelmente está selecionado
onFormSubmit
), escolhacreateFormSubmitTrigger
. - Clique no botão “Run” (ícone de play).
- Autorização: Uma janela “Authorization required” aparecerá. Clique em “Review Permissions”.
- Escolha a conta Google que você está usando (a mesma que tem acesso ao formulário e ao projeto GCP).
- Você verá uma tela “Google hasn’t verified this app”. Isso é normal para scripts pessoais. Clique em “Advanced” e depois em “Go to [Nome do seu projeto] (unsafe)”.
- Revise as permissões que o script está solicitando (gerenciar formulários, conectar-se a serviços externos) e clique em “Allow”.
- A função será executada e você deverá ver “Gatilho onFormSubmit criado com sucesso.” nos logs (View → Logs).
- No menu suspenso acima do código (onde provavelmente está selecionado
- Teste o Formulário: Abra seu Google Form (no modo de preenchimento, não edição) e envie uma resposta de teste.
- Verifique os Logs: Volte ao editor de scripts e vá em “View” → “Executions”. Procure pela execução mais recente de
onFormSubmit
. Clique nela para ver os logs (Logger.log
). Você deve ver a mensagem “Mensagem publicada no Pub/Sub: …” se tudo correu bem, ou mensagens de erro caso contrário. - Verifique o Pub/Sub:
- No Cloud Console, vá para Pub/Sub → Subscriptions. Crie uma nova assinatura (“Create Subscription”) para o seu tópico (
form-submission
). Dê um nome a ela (ex:form-submission-test-sub
), selecione o tópico correto e mantenha o resto como padrão (Pull). - Após criar a assinatura, clique nela e vá para a aba “Messages”.
- Clique em “Pull”. Pode levar alguns segundos, mas você deverá ver a mensagem correspondente à sua resposta do formulário (o conteúdo estará codificado em Base64 na seção “Data”, mas o console geralmente oferece uma opção para decodificá-lo).
- No Cloud Console, vá para Pub/Sub → Subscriptions. Crie uma nova assinatura (“Create Subscription”) para o seu tópico (
Considerações Importantes
- Permissões IAM: Reforçando: O usuário que autoriza o script (geralmente o criador do formulário/script) precisa ter o papel
roles/pubsub.publisher
(ou equivalente) no projeto GCP associado para que a chamadapublishToPubSub
funcione. Se você receber erros 403 Forbidden, verifique as permissões IAM desse usuário no GCP. - Tratamento de Erros: O código inclui tratamento básico de erros (
try...catch
e verificação do código de resposta HTTP). Para produção, você pode querer adicionar um tratamento mais robusto, como notificações de falha. - Quotas e Limites: Esteja ciente das quotas do Google Apps Script (tempo de execução, chamadas
UrlFetchApp
) e do Pub/Sub (throughput, tamanho da mensagem). Para formulários com altíssimo volume, pode ser necessário considerar outras arquiteturas. - Segurança: Se o formulário coletar dados sensíveis, certifique-se de que seu tópico Pub/Sub e os sistemas que consomem dele estejam adequadamente protegidos.
Conclusão
Integrar o Google Forms com o Pub/Sub usando Apps Script abre um leque de possibilidades para automatizar fluxos de trabalho e processar dados em tempo real. Seguindo os passos de configuração do GCP, associando corretamente o projeto Apps Script ao GCP, entendendo o fluxo de autenticação via ScriptApp.getOAuthToken()
e implementando o código fornecido, você pode ter essa integração funcionando rapidamente. Lembre-se sempre de verificar as permissões e testar o fluxo completo!