Tutorial CRUD em Node.js com driver nativo do MongoDB – Parte 3

O tutorial de hoje é uma continuação de uma série bastante acessada aqui no blog, onde ensino como fazer um sistema de cadastro bem simples em Node.js, usando o web framework ExpressJS e o banco de dados não-relacional MongoDB. Ou seja, o famoso CRUD.

Nesta terceira e última parte, introduzo um conceito importante de construção de interfaces que é a modularização da página através do recurso de partial views do EJS (view-engine que estamos usando com ExpressJS) e ensino como dar um “tapa” no visual usando o framework front-end Bootstrap, muito utilizado mundialmente para estruturar aplicações web responsivas e elegantes.

Para conseguir acompanhar todos os códigos, é importante que você tenha realizado a parte anterior ou pelo menos baixe os códigos-fonte que se encontram no formulário ao final do tutorial anterior (parte 2). Caso prefira assistir um vídeo, a primeira parte dessa séria pode ser resumida com este vídeo abaixo que é uma aula gratuita do meu curso de Node.js e MongoDB.

Aproveite!

O conteúdo do post é:

Vamos lá!

Atenção, uma versão ainda mais completa deste tutorial está disponível em videoaula em meu curso de Node.js e MongoDB.

O que são Partial Views?

É muito comum quando estamos construindo aplicações web que certas porções de nossas views (telas) acabem se repetindo. Por causa disso, todas as linguagens de programação para web possuem recursos de partial views, ou seja, de modularização da interface a partir de “partes” da tela que são construídas separadas e depois são montadas em conjunto para que o usuário veja apenas o resultado final, completo.

Fazendo uma analogia com o que fazemos no código backend do Node.js, uma partial view é como se fosse um módulo NPM, que depois usamos o require para carregá-lo em nosso código. Em outras plataformas isso é chamado de import, include, using, etc.

Nossa aplicação é bem simples, possui apenas três views: index, new e error, conforme você vê na imagem abaixo.

Estrutura do projeto
Estrutura de Views

Essas views por sua vez também são mega simples, logo, não há uma reeeaaal necessidade de usar partial views aqui, usaremos mais a título de conhecimento. No entanto, esse conceito é muito poderoso e além de tornar seu código de front-end mais elegante e fácil de ler, ele torna a programação de novas páginas muito mais produtiva, pois sempre aproveitaremos elementos genéricos da interface que serão criados apenas uma vez.

Se olharmos agora para as views index e new, você deve notar que existem muitas tags em comum no início e no fim delas. É por aí que vamos começar a melhorar.

Estrutura que se repete
Estrutura que se repete

Partial views com EJS

Não é de hoje que eu uso EJS (Embedded JavaScript) em meus tutoriais e neste não será diferente. Apesar de não ser a view-engine (motor de visualização) padrão do ExpressJS (esse título é do PUG/Jade), ele é meu favorito pois a curva de aprendizado é ridiculamente baixa, considerando que usa HTML + JS, coisa que todo dev web está careca de saber.

Como não poderia deixar de ser, o EJS possui a funcionalidade de criar partial views (lembro dos meus tempos de ASP.NET em que chamávamos isso de MasterPages…). Isso é bem fácil de fazer, comece criando um arquivo top.ejs (top=topo) na sua pasta views e nele vamos colocar toda a parte comum que teremos no topo de todas páginas do nosso sistema, que é apenas o HTML abaixo por enquanto:

Note que nesta top.ejs estamos usando algumas variáveis JS que devem vir do backend, através do model passado na função render do Node.js, lembra?

Agora vamos criar mais um arquivo novo, o bottom.ejs (bottom=rodapé), também na pasta views e nele vamos colocar toda a parte comum que teremos no rodapé de todas páginas do nosso sistema, que é apenas o HTML abaixo por enquanto:

E agora, como fazemos para as demais views do projeto usarem essas partial views para compor a sua estrutura?

Bem simples, vamos começar pela index.ejs, remova a parte do topo do arquivo que é repetida ao arquivo top.ejs e no lugar desse pedaço, deixe como abaixo, usando o comando ‘include’ para “incluir” a partial view na primeira linha do arquivo:

Note que já incluí também o include para o bottom.ejs no final do arquivo. Na hora que o arquivo HTML vai ser construído para ser enviado ao browser para renderização, o EJS vai ler essa linha e entender que parte desse HTML está em outro arquivo. Ele vai ir nesse outro arquivo, copiar o conteúdo de lá e colar bem nesse local.

Assim, com esses dois includes, nós mantemos nossa aplicação modularizada em três pedações: topo, centro e rodapé, facilitando manutenção e aumentando o reuso de código.

Sim, reuso de código, pois agora nas páginas new.ejs e error.ejs nós podemos fazer os mesmos includes para não ter de repetir aqueles blocos iniciais e finais de HTML. Os ganhos agora são pequenos, mas no futuro, são enormes pois facilitam muito a evolução e manutenção do sistema web.

Eu não vou colocar aqui o código dos outros dois arquivos ejs com os includes, embora você possa baixar o projeto completo no final desse artigo deixando seu e-mail.

Depois de fazer estas alterações, coloque sua aplicação Node para rodar (não esqueça de subir o banco MongoDB também) e você vai ver que nada mudou para o usuário, que a tela continua renderizando do mesmo jeito e que as alterações só servem para ajudar o programador a trabalhar melhor mesmo.

Um dos grandes ganhos desta abordagem vem agora: manutenção. Vamos adicionar o framework front-end Bootstrap nessa aplicação pra dar um “tapa” no visual dela e vamos fazer isso de maneira muito fácil porque já deixamos a aplicação preparada para este tipo de alteração.

Adicionando o Bootstrap

Eu não vou me prolongar muito na teoria do Bootstrap por aqui pois falo bastante disso no meu livro Programação Web com Node.js. Inclusive aquele “B” na capa é o símbolo do Bootstrap (os outros símbolos são o JQuery, o HTML5 e o MongoDB).

Livro Node
Livro Node

Basicamente o Bootstrap é um framework front-end muito popular no mundo inteiro, fornecendo uma estrutura e comportamentos padronizados que muitos devs web sabem como mexer, acelerando o desenvolvimento e manutenção de qualquer sistema que use Bootstrap como padrão para front-end.

É como se os sites tivessem a mesma estrutura básica, entende?

Apesar da estrutura básica ser a mesma, a aparência pode variar enormemente através da customização de arquivos de estilo (CSS).

A aplicação do Bootstrap em um projeto web se dá através de seus arquivos de CSS e de seus arquivos de JavaScript.

Vamos começar pelo arquivo CSS, que é obtido no site oficial e deve ser adicionado no topo do nosso arquivo top.ejs, logo antes da chamada original de CSS que foi colocada pelo express-generator:

Como adicionamos esta linha no top.ejs, TODAS as páginas que incluem essa partial-view vão estar agora com o CSS do Bootstrap. Isso é produtividade na programação!

Note que também adicionei duas meta-tags, conforme sugerido na página do Bootstrap, para garantir máxima compatibilidade com os recursos do framework, como a responsividade em dispositivos móveis.

Agora, vamos adicionar os scripts JS necessários pro Bootstrap funcionar corretamente no arquivo bottom.ejs. Eles devem ser adicionados logo antes da tag de fecha-body:

Só o fato de termos feito essas adições já vão gerar alguns efeitos visuais na nossa aplicação, como pode ver na imagem abaixo:

Mas para despertar todo o “poder embelezador” do Bootstrap em nossa aplicação nós temos de fazer alguns ajustes na nossa estrutura, bem como usar algumas classes CSS definidas pelo Bootstrap.

Assim, vamos começar definindo uma “div class container” que vai englobar todo o conteúdo do body das páginas. Para fazer isso, basta adicionar o conjunto de tags div abaixo, com a abre-div no top.ejs e a fecha-div no bottom.ejs, de modo que ambas fiquem dentro do body.

Note que só mudou uma linha, logo acima do H1, bem no final do top.ejs. Já no bottom.ejs, também só vai mudar uma linha, que fica bem no início do arquivo:

Após essa adição, teremos mais um ajuste perceptível nas páginas já existentes, que ficarão com uma margem e mais centralizadas. A div container faz a sua página funcionar em um grid-system de 12 colunas virtuais, ou seja, o Bootstrap permite que você organize o conteúdo das suas páginas em 12 blocos de tamanhos iguais, como em um Lego. Desde que você siga esta regra cuidadosamente, a sua aplicação web será responsiva, alterando a sua largura conforme a tela do aparelho que estiver acessando a mesma.

E isso é só o início!

Customizando a aparência

Eu poderia ficar aqui durante muitas e muitas horas escrevendo sobre Bootstrap, então vou ser breve. Vamos apenas dar uma embelezada na página para te mostrar o poder do framework e depois vamos encerrar o tutorial. Fica a seu critério depois se aprofundar, seja em meu livro ou na documentação oficial.

Uma vez adicionado a div container, que é o principal bloco da sua página, vamos personalizar os botões, ou os elementos que queremos que se pareçam com botões. Para isso, basta usarmos duas classes em cada elemento “btn btn-primary” para os botões principais e apenas “btn” para os secundários.

Cada âncora ou submit/button deve ficar parecida com o HTML abaixo:

O botão primário é azul no Bootstrap, mas isso obviamente você pode alterar sobrescrevendo ou editando o CSS original do Bootstrap, ou ainda através de templates que você pega na Internet. As classes CSS de botão também já adicionam um efeito de sombra ao passar o mouse por cima deles, o chamado “hover”.

Para “fechar” a tela inicial, vamos customizar a tabela além do botão, para ela ficar bem bacanuda. Para isso, além de usar o padrão HTML5 para tabelas (com thead, tbody, etc), vamos adicionar uma série de classes a saber:

  • table: classe padrão Bootstrap para tabelas;
  • table-bordered: com linhas nas bordas;
  • table-striped: com linhas “zebradas”;
  • table-hover: com sombra quando passa o mouse;
  • thead-dark (no cabeçalho): pro cabeçalho ficar escuro;

O código final que lista os clientes cadastrados pode ser visto abaixo, e substitui a lista antiga:

Fechando de vez esta tela, atualize o código de paginação para ele ficar estilizado conforme recomendado pelo Bootstrap:

Com estas alterações, nossa tela inicial ficará muito melhor do que anteriormente, como mostra a imagem abaixo (coloquei btn-danger ao invés de btn-primary nos botões de exclusão):

Lista de Clientes com Bootstrap

Agora a segunda tela, de cadastro de cliente (new.ejs). Além de ajustarmos os botões com as classes que mencionei antes, vamos ajustar o form HTML conforme instruções do próprio Bootstrap:

O resultado, você confere na imagem abaixo (os tamanhos são ajustáveis, mas por padrão ele é responsivo):

Cadastro com Bootstrap

E com isso encerramos o tutorial de hoje e acredito que esta série sobre o CRUD com driver nativo do MongoDB. Qualquer dúvida que você tiver, deixe aí nos comentários que terei o maior prazer em responder.

Interessado em mais conteúdos sobre Node.js e MongoDB, clique no banner abaixo e conheça o meu curso em videoaulas sobre o assunto!

Curso Node.js e MongoDB
Curso Node.js e MongoDB

Entendendo o Node.js Event Loop

Continuando os estudos de Node.js me deparei com um elemento chave que não temos como ignorar quando o assunto é essa tecnologia. Estou falando do Event Loop.

Grande parte das características e principalmente das vantagens do Node.js se devem ao funcionamento do seu loop single-thread principal e como ele se relaciona com as demais partes do Node, como a biblioteca C++ libuv.

Assim, a ideia deste artigo é ajudar você a entender como o Event Loop do Node.js funciona, o que deve lhe ajudar a entender como tirar o máximo de proveito dele.

Vamos ver neste artigo:

Você pode acompanhar este conteúdo através do vídeo abaixo, que é parte do meu curso de Node.js e MongoDB:

O problema

Antes de entrar no Event Loop em si, vamos primeiro entender porque o Node.js possui um e qual o problema que ele propõe resolver.

A maioria dos backends por trás dos websites mais famosos não fazem computações complicadas. Nossos programas passam a maior parte do tempo lendo ou escrevendo no disco, ou melhor, esperando a sua vez de ler e escrever, uma vez que é um recurso lento e concorrido. Quando não estamos nesse processo de ir ao disco, estamos enviando ou recebendo bytes da rede, que é outro processo igualmente demorado. Ambos processos podemos resumir como operações de I/O (Input & Output) ou E/S (Entrada & Saída).

Processar dados, ou seja executar algoritmos, é estupidamente mais rápido do que qualquer operação de IO que você possa querer fazer. Mesmo se tivermos um SSD em nossa máquina com velocidades de leitura de 200-730 MB/s fará com que a leitura de 1KB de dados leve 1.4 micro-segundos. Parece rápido? Saiba que nesse tempo uma CPU de 2GHz consegue executar 28.000 instruções.

Isso mesmo. Ler um arquivo de 1KB demora tanto tempo quanto executar 28.000 instruções no processador. É muito lento.

Quando falamos de IO de rede é ainda pior. Faça um teste, abra o CMD e execute um ping no site do google.com, um dos mais rápidos do planeta:

A latência média nesse teste é de 44 milisegundos. Ou seja, enviar um ping para o Google demora o mesmo tempo que uma CPU necessita para executar 88 milhões de operações.

Ou seja, quando estamos fazendo uma chamada a um recurso na Internet, poderíamos estar fazendo cerca de 88 milhões de coisas diferentes na CPU.

É muita diferença!

A solução

A maioria dos sistemas operacionais lhe fornece mecanismos de programação assíncrona, o que permite que você mande executar tarefas concorrentes que não ficam esperando uma pela outra, desde que uma não precise do resultado da outra, é claro.

Esse tipo de comportamento pode ser alcançado de diversas maneiras. Atualmente a forma mais comum de fazer isso é através do uso de threads o que geralmente torna nosso código muito mais complexo. Por exemplo, ler um arquivo em Java é uma operação bloqueante, ou seja, seu programa não pode fazer mais exceto esperar a comunicação com a rede ou disco terminar. O que você pode fazer é iniciar uma thread diferente para fazer essa leitura e mandar ela avisar sua thread principal quando a leitura terminar.

Novas formas e programação assíncrona tem surgido com o uso de interfaces async como em Java e C#, mas isso ainda está evoluindo. Por ora isso é entediante, complicado, mas funciona. Mas e o Node? A característica de single-thread dele obviamente deveria representar um problema uma vez que ele só consegue executar uma tarefa de um usuário por vez, certo? Quase.

O Node usa um princípio semelhante ao da função setTimeout(func, x) do Javascript, onde a função passada como primeiro parâmetro é delegada para outra thread executar após x milisegundos, liberando a thread principal para continuar seu fluxo de execução. Mesmo que você defina x como 0, o que pode parecer algo inútil, isso é extremamente útil pois força a função a ser realizada em outra thread imediatamente.

Vamos falar melhor dessa solução na sequência.

Node.js Event Loop

Sempre que você chama uma função síncrona (i.e. “normal”) ela vai para uma “call stack” ou pilha de chamadas de funções com o seu endereço em memória, parâmetros e variáveis locais. Se a partir dessa função você chamar outra, esta nova função é empilhada em cima da anterior (não literalmente, mas a ideia é essa). Quando essa nova função termina, ela é removida da call stack e voltamos o fluxo da função anterior. Caso a nova função tenha retornado um valor, o mesmo é adicionado à função anterior na call stack.

Mas o que acontece quando chamamos algo como setTimeout, http.get, process.nextTick, ou fs.readFile? Estes não são recursos nativos do V8, mas estão disponíveis no Chrome WebApi e na C++ API no caso do Node.js.

Vamos dar uma olhada em uma aplicação Node.js comum – um servidor escutando em localhost:3000. Após receber a requisição, o servidor vai chamar wttr.in/ para obter informações do tempo e imprimir algumas mensagens no console e depois retorna a resposta HTTP.

O que será impresso quando uma requisição é enviada para localhost:3000?

Se você já mexeu um pouco com Node antes, não ficará surpreso com o resultado, pois mesmo que console.log(‘Obtendo a previsão do tempo, aguarde.’) tenha sido chamado depois de console.log(‘Previsão confirmada!’) no código, o resultado da requisição será como abaixo:

O que aconteceu? Mesmo o V8 sendo single-thread, a API C++ do Node não é. Isso significa que toda vez que o Node for solicitado para fazer uma operação bloqueante, Node irá chamar a libuv que executará concorrentemente com o Javascript em background. Uma vez que esta thread concorrente terminar ou jogar um erro, o callback fornecido será chamado com os parâmetros necessários.

A libuv é um biblioteca C++ open-source usada pelo Node em conjunto com o V8 para gerenciar o pool de threads que executa as operações concorrentes ao Event Loop single-thread do Node. Ela cuida da criação e destruição de threads, semáforos e outras “magias” que são necessárias para que as tarefas assíncronas funcionem corretamente. Essa biblioteca foi originalmente escrita para o Node, mas atualmente outros projetos a usam também.

Curso Node.js e MongoDB
Curso Node.js e MongoDB

Task/Event/Message Queue

Javascript é uma linguagem single-thread orientada a eventos. Isto significa que você pode anexar gatilhos ou listeners aos eventos e quando o respectivo evento acontece, o listener executa o callback que foi fornecido.

Toda vez que você chama setTimeout, http.get ou fs.readFile, Node.js envia estas operações para a libuv executá-las em uma thread separada do pool, permitindo que o V8 continue executando o código na thread principal. Quando a tarefa termina e a libuv avisa o Node disso, o Node dispara o callback da referida operação.

No entanto, considerando que só temos uma thread principal e uma call stack principal, onde que os callbacks ficam guardados para serem executados? Na Event/Task/Message Queue, ou o nome que você preferir. O nome ‘event loop’ se dá à esse ciclo de eventos que acontece infinitamente enquanto há callbacks e eventos a serem processados na aplicação.

Em nosso exemplo anterior, de previsão do tempo, nosso event loop ficou assim:

  1. Express registrou um handler para o evento ‘request’ que será chamado quando uma requisição chegar em ‘/’
  2. ele começar a escutar na porta 3000
  3. a stack está vazia, esperando pelo evento ‘request’ disparar
  4. quando a requisição chega, o evento dispara e o Express chama o handler configurado: sendWeatherOfRandomCity
  5. sendWeatherOfRandomCity é empilhado na call stack
  6. getWeatherOfRandomCity é chamado dentro da função anterior e é também empilhado na call stack
  7. Math.floor e Math.random são chamadas, empilhadas e logo desempilhadas, retornando uma cidade à variável city
  8. superagent.get é chamado com o parâmetro ‘wttr.in/${city}’ e definimos o handler/callback para o evento de término da requisição.
  9. a requisição HTTP para http://wttr.in/${city} é enviada para uma thread em background e a execução continua
  10. ‘Obtendo a previsão do tempo, aguarde.’é impresso no console e getWeatherOfRandomCity retorna
  11. sayHi é chamada, ‘Hi’ é impresso no console
  12. sendWeatherOfRandomCity retorna, é retirado da call stack, deixando-a vazia
  13. ficamos esperando pela chamada de http://wttr.in/${city} nos responder
  14. uma vez que a resposta chegue, o evento de ‘end’ é disparado
  15. o handler anônimo que passamos para .end() é chamado, é colocado na call stack com todos as variáveis locais, o que significa que ele pode ver e modificar os valores de express, superagent, app, CITIES, request, response, city e todas funções que definimos
  16. response.send() é chamado com um status code de 200 ou 500, mas isso também é executado em uma thread do pool para a stream de respostas não fique bloqueada e o handler anônimo é retirado da pilha.

E é assim que tudo funciona!

Vale salientar que por padrão o pool de threads da libuv inicia com 4 threads concorrentes e que isso pode ser configurado conforme a sua necessidade.

Microtasks e Macrotasks

Além disso, como se não fosse o bastante, nós temos duas task queues, não apenas uma. Uma task queue para microtasks e outra para macrotasks.

Exemplos de microtasks

  • process.nextTick
  • promises
  • Object.observe

Exemplos de macrotasks

  • setTimeout
  • setInterval
  • setImmediate
  • I/O

Para mostrar isso na prática, vamos dar uma olhada no seguinte código:

a saída no console é:

De acordo com a especificação da WHATWG, uma macrotask deve ser processada da macrotask queue em um ciclo do event loop. Depois que essa macrotask terminar, todas as microtasks existentes são processadas dentro do mesmo ciclo. Se durante este processamento de microtasks novas microtasks surgirem, elas são processadas também, até a microtask queue ficar vazia.

Este diagrama do site Rising Stack ilustra bem o event loop completo:

Em nosso caso:

Ciclo 1:

  1. setInterval é agendado como (macro)task
  2. setTimeout 1 é agendado como task
  3. em Promise.resolve 1 ambos thens são agendados como microtasks
  4. a call stack está vazia e as microtasks executam

Task queue: setInterval, setTimeout 1

Ciclo 2:

  1. a microtask queue está vazia, logo o handler setInterval pode executar;
  2. outro setInterval é agendado como task, logo atrás de setTimeout 1

Task queue: setTimeout 1, setInterval

Ciclo 3:

  1. a microtask queue está vazia, logo o handler setTimeout 1 pode executar;
  2. promise 3promise 4 são agendadas como microtasks;
  3. handlers de promise 3promise 4 são executados
  4. setTimeout 2 é agendado como task

Task queue: setInterval, setTimeout 2

Ciclo 4:

  1. a microtask queue está vazia; logo o handler de setInteval pode executar;
  2. outro setInterval é agendado como task, logo atrás de setTimeout

Task queue: setTimeout 2, setInterval

Ciclo 5:

  1. o handler setTimeout 2 executa;
  2. promise 5promise 6 são agendadas como microtasks;
  3. os handlers de promise 5 e promise 6 executam encerrando o programa.

Nota: isso funciona perfeitamente bem no Google Chrome, mas por questões que fogem da minha compreensão, não é regra em todos ambientes de execução. Existem modificações que podemos fazer no código para que o comportamento seja o mesmo em todos ambientes, mas deixam o código terrivelmente feio (i.e. callback hell).

Conclusões

Como você pôde ver, se quisermos ter total controle de nossas aplicações Node.js devemos prestar atenção nestes detalhes de como as tarefas são executadas dentro do event loop, principalmente para não bloquearmos sua execução sem querer.

O conceito do event loop pode ser um tanto complicado no início mas uma vez que você entender sue funcionamento na prática você não conseguirá mais imaginar sua vida sem ele. Obviamente o uso inicial intenso de callbacks é muito chato de gerenciar mas já é possível usar Promises em nossos códigos Javascript que permitem deixar as tarefas assíncronas mais inteligíveis e em breve devemos ter acesso ao recurso async-await com o ES7.

Uma última dica é que você também pode enviar seus processamentos longos (mas que não são operações de IO), que normalmente seriam executados na thread principal para as threads em background usando bibliotecas como async.js.

Recomendo agora colocar a mão na massa com esse tutorial de Node.js com MongoDB que preparei pra você!

Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js!

Como fazer upload de arquivos para o Google Drive em Node.js

Com meu curso de Node.js e MongoDB chegando aos quase 200 inscritos na data em que escrevo este tutorial, muitas ideias tem me sido enviadas com relação a temas para posts e novas aulas no curso. Recentemente, um aluno estava tentando fazer algo que me chamou a atenção: uma API em Node.js que recebesse um arquivo e o enviasse para o Google Drive.

Assim, no artigo de hoje quero mostrar como você pode criar uma integração do Node.js com o Google Drive facilmente. Vamos enviar imagens, mas você pode facilmente adaptar o código para enviar outro tipo de arquivo.

Vamos lá!

Google Drive

Obviamente para que você consiga acompanhar este tutorial você deve ter uma conta no Google Drive. Se você possui um Gmail, automaticamente possui uma pois seus emails são armazenados na mesma que, em seu nível gratuito, fornece 15GB de armazenamento na nuvem. Por cerca de R$70/ano você faz um upgrade para 100GB o que lhe permite salvar muita coisa de maneira rápida e segura.

Caso não possua uma, crie em drive.google.com

Surpreendentemente, existe todo um suporte do Google à tecnologia Node.js, que você confere neste painel do Google Drive APIs. Acesse o painel e clique no botão “Enable Drive API” para que seja possível se integrar com a sua conta do GDrive, conforme a imagem abaixo.

Google Drive APIs
Google Drive APIs

Ao ativar a API, você receberá um Client ID e um Client Secret, que serão necessários para a autenticação na aplicação Node.js.Guarde-os consigo, pois eu não vou fornecer os meus, hehehe. Também lhe é oferecido um arquivo de credenciais (credentials.json), baixe e salve-o na pasta do projeto que vamos criar a seguir.

Criando o projeto em Node

Crie uma pasta na sua máquina chamada gdrive-node e navegue até ela via terminal. Crie um gdrive-auth.js vazio e rode um ‘npm init’ para criar uma aplicação. Depois instale a biblioteca do GDrive usando o comando abaixo:

Lembre-se de ter o seu arquivo credentials.json dentro da pasta do projeto, pois agora vamos carregá-lo na nossa aplicação. Abra o gdrive-auth.js e inclua o seguinte código, adaptado da documentação do Google Drive APIs:

Basicamente o que temos aqui é o código que implementa a autenticação OAuth offline. Ou seja, a sua aplicação vai solicitar um token para a sua conta do Google Drive, que vai ser utilizada pela sua aplicação. Mais tarde usaremos este módulo para chamar a API do GDrive.

Ao executar esse código pela primeira vez no console (node gdrive-auth) você receberá uma URL que deve ser acessada. Copie a URL e ao acessar a página no navegador, você verá a sua conta do Google e ela vai lhe questionar se você quer conceder acesso à essa aplicação Node (Quickstart). Fornecendo a permissão você receberá o token que deve ser informado no terminal novamente, para que seja gravado.

Se tudo ocorrer bem, um teste deve ser realizado automaticamente listando os 10 últimos arquivos adicionados na sua conta do GDrive. Com isso temos um projeto configurado e autenticado para acessar as APIs do Google Drive (essa autenticação é feita apenas uma vez, para obter o arquivo token.json, que fica na raiz da sua aplicação).

Atenção: o escopo da permissão que solicitamos é para gerenciar pastas e arquivos enviados pela própria aplicação. Sendo assim, no primeiro teste não será listado nenhum arquivo pois a aplicação não criou nada ainda. Nos testes subsequentes, no console serão listados os arquivos que já fizemos upload.

Se precisar mudar o escopo de permissão (na variável SCOPES), certifique-se também de excluir o arquivo token.json para que o processo de autenticação reinicie corretamente e ele seja criado com as permissões corretas.

Enviando uma imagem

Agora vamos criar outro módulo no nosso projeto, em um arquivo gdrive.js, com o seguinte conteúdo, adaptado também da documentação oficial:

Neste módulo nós usamos o módulo anterior, de autenticação, e depois enviamos uma imagem passada como argumento para o GDrive criar ela idêntica na nuvem. O argumento fileName é apenas o nome da imagem enquanto que o filePath é o caminho relativo ou literal. Após a criação, será executado um callback com o ID do arquivo no GDrive que acabamos de criar.

Caso queira fazer upload de outros arquivos que não sejam imagens JPG, basta trocar o mime-type.

Agora que temos um módulo de autenticação e um de upload de imagem, vamos criar um index.js para realizar alguns testes:

Aqui estou considerando que você tem um arquivo chamado imagem.jpg dentro da pasta do projeto, no mesmo nível dos módulos. Rode essa aplicação com “node index” e você deve encontrar o novo arquivo na sua conta do GDrive, na raiz do mesmo.

Agora, com as adaptações certas, você pode usar esse módulo em uma web API Express ou mesmo com algum outro framework do Node, para compor uma solução de verdade.

Espero que tenha gostado!

Curtiu o tutorial? Para mais conteúdos bacanas em texto e videoaulas, conheça o meu curso de Node.js e MongoDB clicando no banner abaixo.

Curso Node.js e MongoDB
Curso Node.js e MongoDB