Como conectar uma aplicação NodeJS com Firebase Firestore

Vamos construir uma API de um Encurtador de URL, utilizando NodeJS, Express, Typescript e armazenamento no Cloud Firestore.

Esta API (completa) está no Github, neste repositório. Fique a vontade para ir direto para lá e pular os detalhes deste tutorial 🙂

Para baixar os arquivos deste tutorial, clique aqui.

Requisitos

Você precisa saber um pouco de Javascript, ter o NodeJS, NPM e um editor de código instalados no seu computador.

Neste post

Sobre o Cloud Firestore

O Cloud Firestore é um banco de dados de documentos NoSQL, similar ao MongoDB (e alguns outros), e pode ser utilizado para aplicativos móveis e web. Você pode utilizá-lo sem a preocupação com a hospedagem do banco e, nem mesmo com o backend já que pode ser acessado utilizando SDKs nativos. O Cloud Firestore também está disponível em SDKs nativos do NodeJS, Java, Python, Unity, C++ e Go, bem como em APIs REST e RPC.

O Firestore trabalha com o conceito de coleções, documentos e dados. Coleções são conjuntos de documentos e estes possuem conjuntos de dados. Se você conhece bem um objeto JSON vai ver que são muito parecidos. Os documentos do Firestore são como JSONs leves, visto que cada um pode ter até 1MB.

Criando o projeto no Firebase

Acesse o console do Firebase para criar um projeto, clique em Add Project e siga os passos abaixo.

Informe o nome do seu projeto
Informe o nome do seu projeto
Deixe as opções de Analytics desabilitadas, ou não
Deixe as opções de Analytics desabilitadas, ou não. Clique em Create project.

Aguarde seu projeto ser criado.

Configurando o banco de dados

No menu lateral esquerdo, clique em Firestore Database, na nova tela clique em Create Database. Uma nova janela irá se abrir, selecione o modo de teste Start in test mode. Clique em Next e depois, Enable e Enable.

Você verá uma janela como esta:

Janela do Cloud Firestore
Janela do Cloud Firestore

Criando a primeira coleção e documento

Clique em Start collection, dê o nome urls e clique em Next. Na janela seguinte crie seu primeiro documento conforme abaixo (clique em Auto-ID para deixar o Firestore gerar o ID do documento).

Gerando uma private key para conexão

Vamos criar uma chave para permitir a conexão da nossa aplicação com o Firestore.

No menu lateral, em Project Overview, clique na engrenagem e depois em Project settings. Na nova tela, vá na aba Service accounts e clique no botão Generate new private key.

Faça o download e guarde esta chave em um lugar seguro. Já já iremos utilizá-la.

Acesse a tela de configurações do projeto
Project settings > Services account > generate new private key
Project settings > Services account > generate new private key

Ao baixar sua chave, observe que ela utiliza o padrão snack_case, altere para CamelCase para que ela seja aceita como objeto de conexão dentro da aplicação. Veja o exemplo abaixo.

Criando a aplicação NodeJS

Crie uma pasta para o novo projeto e dentro desta pasta execute o comando abaixo a partir de um terminal:

npm init -y

Instale as dependências e seus respectivos @types:

npm install cors express firebase-admin mongoose nodemon uniqid
npm install typescript --save-dev
npx tsc --init
npm install @types/cors @types/express @types/mongoose @types/nodemon @types/uniqid --save-dev

Configure o seu tsconfig.json conforme o repositório no Github.

Dentro do arquivo package.json dentro de scripts, adicione o código:

...
"dev": "nodemon ./dist/index.js"
...

Criando as rotas com NodeJS e Express

Crie uma pasta chamada src e, dentro dela crie um arquivo chamado index.ts com o seguinte conteúdo:

import express, { Request, Response } from "express";
import cors from 'cors';

const api = express();

api.use(express.json());
api.use(cors());
api.get('/listar', (req: Request, res: Response) => {
  res.json({
    "listar": "ok"
  });
});
api.post('/cadastrar', (req: Request, res: Response) => {
  res.json({
    "cadastrar": "ok"
  });
});
api.put('/editar/:id', (req: Request, res: Response) => {
  res.json({
    "editar": "ok"
  });
});
api.delete('/excluir/:id', (req: Request, res: Response) => {
  res.json({
    "excluir": "ok"
  });
});
api.listen(1234, () => console.log('Server listening'));

Eu criei as rotas com nomes após o “/”, apenas para fins didáticos, mas em uma aplicação real não será necessário. Utilize apenas os verbos HTTP conforme o exemplo acima.

Agora vamos testar a aplicação. Abra um terminal e rode os comandos abaixo para que os arquivos typescript sejam transpilados a medida em que vamos construindo a aplicação.

tsc -w

Em um novo terminal, execute:

npm run dev

Mantenha os dois terminais abertos para garantir que as alterações feitas no projeto serão automaticamente refletidas no navegador ou na ferramenta que estivermos utilizando para testar.

Agora acesse o navegador/postman/insomnia, digite o endereço http://localhost:1234/listar. Você deve receber de volta um JSON:

{
 "listar": "ok"
}

Conectando o Firestore com NodeJS

A documentação do Firestore oferece algumas opções para conexão e manipulação dos dados, você pode conferir aqui.

Lembra da private key que você baixou? Jogue o arquivo dentro da pasta src do projeto e renomeie para key.json.

Crie um arquivo chamado firestore.ts dentro da pasta src com o seguinte código:

import * as admin from "firebase-admin";
import * as serviceAccount from "./key.json";

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});
const firestore = admin.firestore();
export default firestore;

Ao importar o firebase-admin teremos acesso a tudo que precisamos para conectar e manipular os dados dentro do Firestore.

Manipular os documentos no Firestore com NodeJS

Vamos importar o arquivo firestore.ts dentro do arquivo index.ts.

import firestore from './firestore';
Funções disponíveis dentro do firestore
Funções disponíveis dentro do firestore

Para recuperar a lista de documentos dentro da nossa coleção urls vamos utilizar o código:

firestore.collection("urls").get();

Aqui estamos fazendo uma busca em um banco de dados e esse processo é um pouco demorado, por isso deve ser uma chamada assíncrona. Acrescente await e transforme a função da rota em async function. Nossa rota ficará da seguinte forma:

api.get('/listar', async (req: Request, res: Response) => {
  const querySnapshot = await firestore.collection("urls").get();
  const list: Array<any> = [];
  querySnapshot.forEach(doc => {
    list.push({
      "id": doc.id,
      "url": doc.data().url_original,
      "hash": doc.data().url_hash
    });
  });
  res.json(list);
});

Para adicionar um novo documento em nossa coleção vamos utilizar:

firestore.collection("urls").add();

Nossa rota de cadastro ficará assim:

api.post('/cadastrar', async (req: Request, res: Response) => {
  const {url} = req.body;
  const {id} = await firestore.collection("urls").add({
    "url_hash": unidid.time(),
    "url_original": url
  });
  const data = await firestore.collection("urls").doc(id).get();
  res.json(data.data());
});

Edição e exclusão:

api.put('/editar/:id', async (req: Request, res: Response) => {
  const {url} = req.body;
  await firestore.collection("urls").doc(req.params.id).update({
    "url_original": url
  });
  res.json({
    "success": true
  });
});

api.delete('/excluir/:id', async (req: Request, res: Response) => {
  await firestore.collection("urls").doc(req.params.id).delete();
  res.json({
    "success": true
  });
});

Conclusão

O Firestore possui muitas funcionalidades interessantes para incrementar um projeto como a possibilidade de adicionar listeners e fazer atualizações de uma aplicação em tempo real, criar sub-documentos e mapas aninhados, integrar com a autenticação do próprio Firebase para um MVP, mas esse tutorial é um começo para você se aprofundar neste assunto.

Conhecimento é algo que ninguém pode tirar de você e quando é compartilhado não se perde, multiplica.

Um comentário

Os comentários estão fechados.