Função do Cloud para automatizar a importação de dados CSV para o app Planilhas Google

1. Introdução

O objetivo deste codelab é ensinar você a criar uma função do Cloud para reagir ao upload de um arquivo CSV no Cloud Storage, ler o conteúdo dele e usar esse recurso para atualizar um arquivo das Planilhas Google com a API Sheets.

e9c78061022a6760.png

Isso pode ser visto como a automação de uma "importação como CSV" manual etapa. Isso garante que você possa analisar os dados (talvez produzidos por outra equipe) em uma planilha assim que ela estiver disponível.

A implementação vai ficar assim :

52df703605ae4bd3.png

2. Configuração e requisitos

Configuração de ambiente autoguiada

  1. Faça login no Console do Cloud e crie um novo projeto ou reutilize um existente. Crie uma se você ainda não tiver uma conta do Gmail ou do G Suite.

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Lembre-se do código do projeto, um nome exclusivo em todos os projetos do Google Cloud. O nome acima já foi escolhido e não servirá para você. Faremos referência a ele mais adiante neste codelab como PROJECT_ID.

  1. Em seguida, será necessário ativar o faturamento no Console do Cloud para usar os recursos do Google Cloud.

A execução deste codelab não será muito cara, se for o caso. Siga todas as instruções na seção "Limpeza", que orienta você sobre como encerrar recursos para não incorrer em cobranças além deste tutorial. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

3. Criar e configurar um arquivo das Planilhas Google e ativar a API

Primeiro, vamos criar um novo documento do Planilhas (essa planilha pode pertencer a qualquer usuário). Uma vez criado, lembre-se de seu identificador. ele será usado como uma variável de ambiente para a função que escreveremos :

dd77d5fc1364ad3e.png

No Console do GCP, ative a API Google Sheets em seu projeto recém-criado em "APIs and Services". e depois em "Biblioteca de APIs" :

c64e2e98b8b55f16.png

Na página "IAM e administrador" acesse "Contas de serviço" e anote o e-mail da conta de serviço padrão do App Engine. Ele precisa estar no formato your-project-id@appspot.gserviceaccount.com. Também é possível criar sua própria conta de serviço dedicada a essa ação.

6e279d7e07d4febf.png

Por fim, basta conceder a essa conta de serviço privilégios de edição da planilha usando a opção botão :

c334062465ddf928.png

Com essa configuração, já podemos escrever nossa função do Cloud e configurá-la para usar esta conta de serviço. Ela poderá gravar neste documento de planilha que acabamos de criar.

4. Criar um bucket de armazenamento

Vamos criar o bucket que nossa função do Cloud vai monitorar em busca de novos arquivos CSV.

No console, use o menu à esquerda para acessar "Armazenamento"... :

2ddcb54423979d25.png

Crie um novo bucket com o nome csv2sheet-POSTFIX e substitua POSTFIX por algo exclusivo com todas as outras configurações definidas com os valores padrão :

dd637080ade62e81.png

5. Criar a função do Cloud

Agora é possível criar uma função do Cloud chamada csv2sheet, que é acionada quando há uploads de arquivos em um bucket específico do Cloud Storage. O código será escrito em Node.js 8 com funções assíncronas no editor in-line diretamente no console do Cloud :

6ee1a5ce63174ae8.png.

Defina o gatilho como "Cloud Storage". e para ajustar o nome do bucket ao que você criou na etapa anterior.

Atualize também o ponto de entrada da função que estamos prestes a gravar em csv2sheet :

446e7c7c992c2d8a.png

Agora mude o corpo da função para :

  1. usar as APIs Cloud Storage e Sheets
  2. marque a função csv2sheet como async.
  3. receba o fileName dos metadados de evento do Cloud Storage e crie um nome para a nova planilha que vamos criar :
const {google} = require("googleapis");
const {Storage} = require("@google-cloud/storage")

exports.csv2sheet = async (data, context) => {
  var fileName = data.name;
  // basic check that this is a *.csv file, etc...
  if (!fileName.endsWith(".csv")) {
    console.log("Not a .csv file, ignoring.");
    return;
  }
  // define name of new sheet  
  const sheetName = fileName.slice(0, -4);

  // TODO!
};

O uso de async aqui é necessário para usar await, como veremos em breve.

Algumas opções importantes durante a criação dessa função incluem (clique no link "Mais" na parte inferior da tela) :

  • Use o menu suspenso para selecionar a conta de serviço discutida acima
  • Defina uma variável de ambiente chamada SPREADSHEET_ID que corresponda ao documento de planilha que você criou anteriormente :

fd22d1873bcb8c66.png

Como etapa final da configuração, veja o conteúdo de package.json com as APIs Cloud Storage e Planilhas Google como as duas dependências que usaremos (use a guia PACKAGE.JSON do editor in-line do console) :

{
    "name": "csv2sheet",
    "version": "0.0.42",
    "dependencies": {
        "googleapis": "^51.0.0",
        "@google-cloud/storage": "^5.0.1"
    }
}

Depois de configurar tudo conforme descrito, clique em "Criar" ! Após um breve minuto, a função será criada e implantada.

6. Configurar autenticação e API Sheets

Antes de escrevermos mais códigos na função do Cloud usando o editor in-line, precisamos bloquear a criação de uma API de cliente do Google com os escopos adequados do Storage e do Planilhas. Isso faz parte de uma função async.

No editor de funções do console, clique em EDITAR. e adicione o seguinte código ao corpo da função csv2sheet :

// block on auth + getting the sheets API object
const auth = await google.auth.getClient({
  scopes: [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/devstorage.read_only"
  ]
});

A partir daí, podemos criar um cliente da API Sheets :

const sheetsAPI = google.sheets({version: 'v4', auth});

7. Usar a API Sheets para criar uma página vazia

Com um cliente da Sheets API, podemos criar uma nova planilha simples em nosso documento, mas antes de continuarmos, aqui está uma rápida observação sobre o vocabulário:

  • uma planilha é o documento real e é referenciada por seu identificador (discutido acima e visível no URL do documento)
  • uma planilha é uma das guias no documento e pode ser referenciada por seu nome (o nome da guia) ou por um identificador gerado na criação da página

Pensando nisso, esta é uma função que usa o cliente da API Sheets para criar uma planilha vazia na posição 2 (normalmente após a "Sheet1 padrão"), com 26 colunas e 2.000 linhas, com a primeira linha congelada (adicione-a à sua função usando o editor in-line) :

function addEmptySheet(sheetsAPI, sheetName) {
  return new Promise((resolve, reject) => {
    const emptySheetParams = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            addSheet: {
              properties: {
                title: sheetName,
                index: 1,
                gridProperties: {
                  rowCount: 2000,
                  columnCount: 26,
                  frozenRowCount: 1
                }
              }
            }
          }
        ]
      }
    };
    sheetsAPI.spreadsheets.batchUpdate( emptySheetParams, function(err, response) {
        if (err) {
          reject("The Sheets API returned an error: " + err);
        } else {
          const sheetId = response.data.replies[0].addSheet.properties.sheetId;
          console.log("Created empty sheet: " + sheetId);
          resolve(sheetId);
        }
      }
    );
  });
}

Observe que, em vez de codificar a referência à planilha, usamos a variável de ambiente SPREADSHEET_ID criada anteriormente.

Precisamos nos lembrar de sheetId para outras solicitações feitas a essa página específica. Além disso, o nome da planilha precisa ser exclusivo. Se já houver uma página chamada sheetName, a criação falhará.

A função batchUpdate na API Sheets é uma maneira comum de interagir com documentos e está descrita aqui.

8. Ler dados de um arquivo CSV de armazenamento

Agora que temos um lugar para despejar os dados, vamos desenvolver a função do Cloud no editor in-line e usar a API Cloud Storage para extrair os dados reais do arquivo que acabou de ser enviado e armazená-los em uma string:

function readCSVContent(sheetsAPI, file, sheetName) {
  return new Promise((resolve, reject) => {
    const storage = new Storage();
    let fileContents = new Buffer('');
    storage.bucket(file.bucket).file(file.name).createReadStream()
    .on('error', function(err) {
      reject('The Storage API returned an error: ' + err);
    })
    .on('data', function(chunk) {
      fileContents = Buffer.concat([fileContents, chunk]);
    })  
    .on('end', function() {
      let content = fileContents.toString('utf8');
      console.log("CSV content read as string : " + content );
      resolve(content);
    });
  });
}

9. Preencher a planilha recém-criada

Agora é hora de preencher a planilha que criamos usando a mesma API de cliente do Planilhas e os dados que acabamos de coletar. Aproveitamos a oportunidade para também adicionar estilos às colunas da planilha (alterando o tamanho da fonte da linha superior e deixando-a em negrito) :

function populateAndStyle(sheetsAPI, theData, sheetId) {
  return new Promise((resolve, reject) => {
    // Using 'batchUpdate' allows for multiple 'requests' to be sent in a single batch.
    // Populate the sheet referenced by its ID with the data received (a CSV string)
    // Style: set first row font size to 11 and to Bold. Exercise left for the reader: resize columns
    const dataAndStyle = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            pasteData: {
              coordinate: {
                sheetId: sheetId,
                rowIndex: 0,
                columnIndex: 0
              },
              data: theData,
              delimiter: ","
            }
          },
          {
            repeatCell: {
              range: {
                sheetId: sheetId,
                startRowIndex: 0,
                endRowIndex: 1
              },
              cell: {
                userEnteredFormat: {
                  textFormat: {
                    fontSize: 11,
                    bold: true
                  }
                }
              },
              fields: "userEnteredFormat(textFormat)"
            }
          }       
        ]
      }
    };
        
    sheetsAPI.spreadsheets.batchUpdate(dataAndStyle, function(err, response) {
      if (err) {
        reject("The Sheets API returned an error: " + err);
      } else {
        console.log(sheetId + " sheet populated with " + theData.length + " rows and column style set.");
        resolve();
      }
    });    
  });
}

Esse código deve ser adicionado à função do Cloud, que está 99% concluída.

Observe como os dados e o estilo são combinados como vários requests em uma única chamada batchUpdate da API Sheets. Isso torna a atualização mais eficiente e atômica.

Observe também que definimos um intervalo de edição que corresponde ao tamanho da página que criamos. Isso significa que o conteúdo que excede 26 colunas (o valor columnCount usado ao criar a planilha) vai apresentar falha com esse código específico.

Se tudo correr bem, neste ponto você pode:

  1. salve a função atualizada
  2. solte um arquivo CSV no bucket
  3. ver os dados correspondentes aparecer em sua planilha!

10. Como reunir tudo e testar o fluxo

As chamadas para as funções que acabamos de discutir podem ser feitas como chamadas de bloqueio sucessivas na função csv2sheet original:

  const sheetId = await addEmptySheet(sheetsAPI, sheetName);
  const theData = await readCSVContent(sheetsAPI, data, sheetName);
  await populateAndStyle(sheetsAPI, theData, sheetId);

Se você precisar do código-fonte completo da função, acesse aqui (provavelmente mais fácil de encontrar tudo em um conjunto).

Quando tudo estiver no lugar, basta fazer upload de um arquivo CSV para o bucket correto e ver sua planilha ser atualizada com uma nova planilha com o conteúdo do arquivo. Este é um exemplo de arquivo CSV, caso você não tenha um.

1efae021942e64fa.png

Faça upload de vários arquivos para o bucket e veja o que acontece.

11. Pronto! Hora de eliminar a infraestrutura

Brincadeira, não há infraestrutura para desmontar. Tudo isso é feito sem servidor.

Se quiser, você pode excluir a função do Cloud e o bucket que você criou ou até mesmo todo o projeto.

12. A seguir

Isso conclui este codelab mostrando as etapas para detectar uploads de um bucket do Cloud Storage em uma função do Cloud e atualizar uma planilha Google usando a API apropriada.

Confira o que fazer a seguir:

Se você tiver problemas com este codelab, informe-os no link no canto inferior esquerdo.

Seu feedback é muito importante.