Criando uma API REST sem servidor com Node.js e MongoDB

O movimento sem servidor ganhou um pouco de impulso nos últimos meses. Todo mundo parece estar falando sobre isso. Alguns até chamariam de revolução! Mas, não nos excitamos demais. Não seja como eu. Eu também gosto muito de coisas legais como esta e comece a escrever artigos. Se isso é tudo novo para você, aqui está uma peça que escrevi há algum tempo, explicando os conceitos básicos.

Um curso intensivo no Serverless com Node.js
Independentemente do seu fundo do desenvolvedor, é inevitável que você tenha ouvido o termo Serverless no ano passado. A palavra … hackernoon.com

Nesse espírito, o tempo que investirei em explorar o que é razoável construir usando a arquitetura sem servidor talvez exceda o que é visto como saudável. Minha conclusão é que praticamente tudo é elegível para ser construído de forma sem servidor. A única pergunta que você precisa perguntar é se você realmente precisa disso. Lambdas são apátridas, o que significa que todo o conceito de escrever o código do lado do servidor precisa ser aprendido novamente.

Parece divertido? Sim, é para mim também. Recentemente, publiquei um curso prático sobre o uso da arquitetura sem servidor na vida real. Eu derramei todas as minhas descobertas e razões sensíveis para usar o Serverless neste curso. Eu continuava me perguntando a pergunta “Por que eu preciso de Serverless?” Durante todo o processo de criação. Você pode encontrar meus pensamentos abaixo.

JavaScript sem servidor por exemplo [Vídeo] – Vídeo | Agora, apenas US $ 5
Torne-se habilidoso com demonstrações ao vivo no desenvolvimento web sem servidor www.packtpub.com

Por que usar Serverless para APIs REST?

Por que não? É porque podemos, ou vemos uma clara vantagem em relação aos servidores tradicionais? Ambos os lados da moeda têm argumentos válidos. O Serverless é concebido como sempre. Porque você não precisa gerenciar nada, não se preocupe com o tempo de atividade, isso só funcionará. Ele também escala automaticamente. Isso é bom. Realmente legal. Escalar servidores não é divertido.

Mas e quanto ao armazenamento persistente? Não podemos girar um banco de dados MongoDB em um servidor, como está acostumado. No entanto, se você seguiu o estilo de vida “separação de preocupações” que tem aumentado no ano passado, você já pode ser usado para separar seu banco de dados do seu back-end. Ainda mais, se você estiver acostumado a escrever microservices. Você acaba de dar ao seu aplicativo um URL de conexão e há o banco de dados pronto para ir.

Você está para um desafio?

Este artigo irá mostrar-lhe como ligar um banco de dados MongoDB como um serviço para uma API REST sem servidor. Talvez um pouco cheeky, uma vez que a maneira preferida de usar o AWS Serverless Architecture é com o seu NoSQL DBaaS chamado DynamoDB . Mas eu gosto de combinar coisas estranhas. E, para ser sincero, o Atlas MongoDB é impressionante. É o próprio DBaaS do MongoDB. Você pode obter um cluster MongoDB dedicado gratuitamente.

O que é fantástico com esta configuração é que eu vou mostrar-lhe como escrever código da maneira que você já está acostumado. Tudo o que você sabe trabalhando com o Node.js, Express e Mongoose será reutilizado neste tutorial.

O que há de novo, é a mentalidade por trás do uso do serviço de computação Lambda . Uma função Lambda AWS é basicamente um recipiente Docker . Uma vez que a Lambda é invocada, o recipiente gira e executa o código. Isto é, quando queremos inicializar a conexão do banco de dados, a primeira vez que a função é invocada, quando o contêiner Docker é inicializado pela primeira vez. Cada pedido subseqüente para a função Lambda deve usar a conexão de banco de dados existente. Simples o suficiente? Vamos começar a bater!

Ficando em funcionamento

Eu assumirei que você já tenha uma compreensão básica do framework Serverless. Também espero que você tenha uma conta AWS configurada. Se você não fizer isso, por favor veja o artigo que eu liguei no topo .

1. Criando um serviço

Em primeiro lugar, vamos criar um novo serviço para manter todo o nosso código.

 $ sls criam -t aws-nodejs -p rest-api && cd rest-api

Este comando irá armazenar todos os arquivos e códigos necessários para criar nossas funções Lambda e eventos do Gateway da API. Isso fará isso no caminho que damos com o sinalizador -p . O que significa que irá criar um diretório chamado rest-api . Queremos mudar para esse diretório e trabalhar a partir daí.

2. Instalando módulos

Existem alguns módulos que precisamos. Antes de tudo, precisamos do plugin offline sem servidor para poder executar o nosso código localmente antes de implementar o AWS. Então precisamos pegar mangustão , meu ORM de escolha e dotenv , porque eu não gosto de pressionar as chaves para o GitHub. Empurrar chaves para o GitHub é uma merda. Não faça isso. Toda vez que você empurra uma chave para o GitHub, um pingente de bebê morre. Quero dizer, na verdade, mas ainda assim é tão ruim assim.

Certifique-se de que você está no diretório rest-api . Primeiro, instale Serverless Offline, depois mangusto e dotenv.

 $ npm init -y 
 $ npm i --save-dev serverless-offline 
 $ npm eu - salve mongoose dotenv

É isso, vamos fazer uma pausa do terminal e passar para o Atlas para criar um banco de dados.

3. Criando um banco de dados no Atlas MongoDB

Pronto para mais alguma configuração? Sim, ninguém gosta dessa parte. Mas está nua comigo. Ir para o Atlas MongoDB e inscrever-se.

MongoDB totalmente gerenciado, hospedado em AWS, Azure e GCP
O MongoDB Atlas é um serviço MongoDB hospedado na nuvem projetado e executado pela mesma equipe que constrói o banco de dados. É … www.mongodb.com

É grátis e não é necessário cartão de crédito. Será a caixa de areia que precisamos para brincar. Depois de configurar a sua conta, abra a página da sua conta e adicione uma nova organização.

Adicione um nome que você pensa que se encaixa, eu vou ficar com o rest-api . Pressione em seguida e vá em frente e crie a organização.

Agradável. Isso irá levá-lo para a página da organização. Pressione o botão do novo projeto.

Isso abrirá uma página para nomear seu projeto. Basta digitar o rest-api novamente e acertar próximo.

MongoDB se preocupa com permissões e segurança para que o Atlas mostre outra página de permissões de gerenciamento. Podemos ignorar isso por enquanto e criar o projeto.

Phew, lá nós o temos. Finalmente, podemos criar o cluster real! Pressione o enorme botão verde “Criar um novo cluster” . Isso abrirá uma enorme janela de criação de cluster. Você pode deixar tudo padrão, apenas certifique-se de escolher o tamanho da instância M0 e desabilitar backups.

Depois de tudo isso, basta adicionar um usuário de administrador para o cluster e dar-lhe uma senha muito forte. Como você pode ver, o preço desse cluster será de US $ 0,00 / para sempre . Até legal. É isso, acerte “Confirmar e implantar” .

Seu cluster demorará alguns minutos para implantar. Enquanto isso está em andamento, vamos começar a escrever algum código.

Escrevendo algum código

Essa configuração foi um punhado. Agora precisamos pular para escrever a configuração do recurso no arquivo serverless.yml e adicionar os métodos CRUD reais ao handler.js .

4. Configure todos os YAML

A grandeza da estrutura sem servidor reside nos grandes andaimes iniciais. Você pode criar uma ótima configuração usando apenas o código comentado no arquivo serverless.yml . Mas, porque eu sou um odor para a limpeza, vamos simplesmente excluí-lo e adicionar o código abaixo. Depois de copiá-lo para o seu arquivo serverless.yml , irei em frente e expliquei tudo.

Esta configuração é simples e apenas o suficiente para nossas necessidades. Definimos o tamanho máximo da memória dos Lambdas para 128 MB, o que é mais do que suficiente para nossas necessidades. Depois de testá-los sozinhos por alguns dias, eles nunca ultrapassaram os 50MB.

Vamos chegar às coisas interessantes, a seção de funções . Adicionamos um total de 5 funções: criar , getOne , getAll , atualizar e excluir . Todos eles apontam para designar funções exportadas de forma idêntica no arquivo handler.js . Seus caminhos seguem a convenção de nomeação de uma API REST padrão. Surpreendentemente, como isso é tudo, precisamos configurar os recursos do Gateway da API para desencadear nossas funções Lambda.

Isso é praticamente isso, o último é adicionar uma seção de plugins e serverless-offline . Nós instalamos este módulo acima e nós o usaremos para testar o serviço antes de implementar o AWS. Eu acho que estamos prontos para jogar com o handler.js em seguida. Vamos!

5. Criando as funções

Estamos prontos para se divertir de verdade agora. Em primeiro lugar, definiremos as 5 funções que precisamos e criamos o layout inicial do comportamento que queremos. Depois disso, podemos criar a conexão do banco de dados e adicionar a lógica de interação do banco de dados com o Mongoose.

Primeiro, abra o arquivo handler.js . Você verá a função padrão do hello. Vá em frente e exclua tudo e adicione o código abaixo.

Passo 1 de adicionar lógica ao handler.js

Ok, está bom ficar um pouco sobrecarregado. Mas, não há necessidade de se preocupar. Estas são apenas 5 funções simples. Cada função tem o mesmo valor de context.callbackWaitsForEmptyEventLoop definido como false , e comece com a chamada de função connectToDatabase() . Uma vez que a função connectToDatabase() resolva, ela continuará com a execução da interação do banco de dados através do Mongoose. Usaremos os métodos do modelo Note para a interação real do banco de dados. Mas espere, não definimos ou criamos nada disso! Você deve estar se perguntando o que há de errado comigo. Bem, eu fiz isso de propósito, primeiro quero que você veja que isso não é tão complicado, nem diferente de criar uma API REST com Node.js e Express.

Nota : context.callbackWaitsForEmptyEventLoopPor padrão, o retorno de chamada aguardará até que o loop de eventos do tempo de execução do Node.js esteja vazio antes de congelar o processo e retornar os resultados ao chamador. Você pode definir esta propriedade como falsa para solicitar a AWS Lambda congelar o processo logo após a callback , mesmo que haja eventos no loop de eventos. A AWS Lambda congelará o processo, quaisquer dados de estado e os eventos no loop de eventos do Node.js (quaisquer eventos restantes no loop de eventos processados ??quando a função Lambda for chamada em seguida e se AWS Lambda optar por usar o processo congelado).
Documentação AWS

Chegou a hora de adicionar a conexão de banco de dados real. O que é importante entender antes de adicionar o código é que a conexão será estabelecida uma vez. Quando o Lambda é invocado pela primeira vez, o que é chamado de início a frio, o AWS girará um recipiente Docker para executar o código. Isto é, quando nos conectamos ao banco de dados. Todas as solicitações subsequentes usarão a conexão de banco de dados existente. Conceitualmente, é bastante fácil de entender, mas um punhado real quando precisamos envolver nossas cabeças em torno dele no código. Aqui vai.

6. Adicionando a conexão do banco de dados

O processo de conexão ao MongoDB é duplo. Precisamos criar uma maneira dinâmica de criar a conexão, mas também certifique-se de reutilizar a mesma conexão se estiver disponível. Vamos começar lento.

Crie um novo arquivo no diretório raiz do serviço, ao lado do handler.js . Dê um nome bastante lógico de db.js e adicione o código abaixo.

Nota : Esta sintaxe é válida para o Mongoose 5.0.0-rc0 e acima. Não funcionará com qualquer versão do mangusto que seja inferior a 5.

Na linha 1, estamos exigindo o Mongoose, assim como estamos acostumados, e na linha 2, adicionando a biblioteca de promessas nativas para ser usada por Mongoose. Isso é porque queremos que o .then s funcione corretamente no handler.js quando os chamamos com os métodos do modelo Note .

E quanto à variável isConnected então? Estamos criando um fechamento e tratando isConnected como o atual estado do banco de dados no contêiner do Docker em execução. Dê uma olhada na função connectToDatabase que exportamos. Na linha 12, estamos estabelecendo uma conexão com uma cadeia de conexão que forneceremos através de uma variável de ambiente. Esta função retorna uma promessa que nós simplesmente. .then devolvemos um objeto db . Este objeto representa a conexão atual e tem uma propriedade de particular interesse para nós. O .readyState nos informará se existe ou não uma conexão. Se sim, igual será 1 caso contrário, é 0 .

Estamos basicamente armazenando em cache a conexão do banco de dados, certificando-se de que não será criado se já existir. Nesse caso, apenas resolvemos a promessa imediatamente.

Com o arquivo db.js criado, vamos exigi-lo no handler.js . Basta adicionar este snippet ao topo do manipulador.

 // top of handler.js 
 const connectToDatabase = require ('./ db');

7. Adicionando um modelo de nota

Dê uma olhada no handler.js. Você pode ver que estamos chamando o modelo Note nas funções para recuperar dados, mas não existe um modelo definido. Bem, agora é tão bom quanto qualquer.

Crie uma nova pasta no diretório raiz do serviço e nomeie modelos . Nela crie outro arquivo e nomeie-o Note.js. Este será apenas um esquema simples de mangusto e uma definição de modelo.

Vamos exportar o próprio modelo para que possamos usá-lo no handler.js . É isso em relação à conectividade do banco de dados. Nós só precisamos adicionar outra declaração necessária para o topo do manipulador e estamos bem para ir.

 // top of handler.js 
 const connectToDatabase = require ('./ db'); 
 const Note = require ('./ models / Note');

Ótimo, agora o que resta é adicionar uma variável de ambiente para manter nosso URL de conexão de banco de dados MongoDB. Essa é uma brisa com o dotenv .

8. Usando dotenv para variáveis ??de ambiente

Deixar arquivos de configuração e chaves em um arquivo totalmente separado é incrivelmente fácil com o dotenv e um salvador de vida real. Você apenas adiciona o arquivo a .gitignore e assegure-se de que não arrisque comprometer quaisquer chaves. Deixe-me te mostrar.

Adicione um novo arquivo, ligue para variables.env . Certifique-se de colocá-lo no diretório raiz do serviço. O arquivo em si só terá uma linha, e esse é o nome da variável de ambiente ao lado do valor. Deve parecer um pouco assim.

 DB = mongodb: // <usuário>: <senha> @ mongodb.net:27017/db

Mas, primeiro precisamos encontrar o URL de conexão. Para isso, precisamos voltar para o Atlas. Na página de clusters principal do projeto que você criou anteriormente, você verá que seu cluster foi criado. Tem um botão de conexão que queremos pressionar.

Ele abrirá um novo pop-up onde você precisará adicionar um endereço IP à lista branca, para que você possa acessar o banco de dados. Então você pega o URL de conexão pressionando o botão “Conectar sua aplicação” .

Depois de pressionar “Conectar sua aplicação”, você será solicitado a ” Copiar uma string de conexão” . Pressione ” Estou usando o driver 3.4 ou anterior” e você pode FINALMENTE copiar o URL. Whoa, esse foi um passeio cansativo.

Depois de copiá-lo, volte para o arquivo variables.env e adicione o URL de conexão real.

 DB = mongodb: // dbadmin: reallystrongpassword@cluster0-shard-00-00-e9ai4.mongodb.net : 27017, cluster0-shard-00-01-e9ai4.mongodb.net: 27017, cluster0-shard-00-02- e9ai4.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin

Certifique-se de não adicionar espaços entre o DB e o URL de conexão. Altere <password> para a senha que você definiu anteriormente. O meu era “verdadeira senha”. O que vai acontecer agora? Bem, as variáveis ??neste arquivo serão carregadas no objeto process.env em Node.js, o que significa que você pode acessá-las da maneira padrão que você já usou.

Nota : Não esqueça de adicionar as variáveis.env ao .gitignore!

Por último, antes de saltar para testar tudo, precisamos exigir o módulo dotenv e apontar para o arquivo onde estamos mantendo as variáveis ??de ambiente. Adicione este trecho ao topo do seu arquivo handler.js .

 requer ('dotenv'). config ({caminho: './variables.env'});

É isso aí. Tempo para experimentá-lo.

Que tal alguns testes?

Estamos prontos para testar a API. Antes de tudo, precisamos executar o Serverless Offline. Mas, por causa da definição do modelo Mongoose, temos na Note.js há uma bandeira que precisamos adicionar ao executá-la.

 $ sls offline start --skipCacheInvalidation

Nota : Como o Serverless Offline invalida o Nó requerem cache em cada execução por padrão, adicionamos esse sinalizador para desativá-lo. Em Node.js quando você require() um módulo, ele armazena uma versão em cache do módulo, de modo que todas as chamadas subsequentes para require() não precisam recarregar o módulo do sistema de arquivos.

Depois de executar o comando no terminal, você deve ver algo assim.

Todas as nossas rotas estão funcionando. Abra seu cliente REST de escolha, Postman, Insomnia ou o que você preferir, e vamos continuar com o teste.

Usando Insomnia , criei um pedido POST para http://localhost:3000/notes com um corpo JSON.

Verificando o terminal que você pode ver => using new database connection é logado, o que significa que a conexão inicial do banco de dados foi estabelecida. Envie outra solicitação de POST e você verá => using existing database connection logado.

Incrível, adicionando uma nova nota funciona. Vamos recuperar a nota que acabamos de adicionar usando o método getOne . Copie o _id da resposta e cole-o no URL do pedido GET.

Recuperar uma única nota também funciona bem. E sobre recuperá-los todos. Basta apagar o parâmetro do percurso da rota ID e acertar “Enviar” mais uma vez.

Apenas dois mais para testar, os métodos de edição e eliminação. Escolha um dos _id s das notas recuperadas e adicione-o como um parâmetro de caminho mais uma vez. Agora altere o método para PUT e adicione um corpo JSON. Digite um título e uma descrição diferentes e pressione “Enviar” .

A edição funciona bem, assim como nós queríamos. Apenas a eliminação esquerda. Mude para o método DELETE, remova o corpo da solicitação e pressione “Enviar” uma última vez.

A nota foi excluída com sucesso. Isso é mais do que suficiente em relação ao teste. Estamos prontos para implantar o serviço no AWS.

Ser responsável pela implantação e monitoramento

Phew, é um monte de coisas que você precisa para envolver sua cabeça. Estamos no trecho da casa. A única coisa que resta é implantar o serviço e certificar-se de que está se comportando da maneira que queremos usando uma ferramenta de monitoração chamada Dashbird .

9. Implantação

O framework Serverless torna as implantações rápidas e indoloras. Tudo o que você precisa fazer é executar um comando.

 $ sls deploy

Ele irá fornecer recursos automáticos em AWS, empacotar e empurrar todo o código para S3 de onde ele será enviado para o Lambdas. O terminal deve mostrar uma saída similar a esta.

Nota : Você pode repetir o processo de teste de cima com os pontos finais fornecidos.

Isso é tudo o que existe no processo de implantação. Fácil, certo? É por isso que eu amo tanto o framework Serverless.

10. Monitoramento

Vamos embrulhar isso com outra ferramenta legal. Eu monitorei meu Lambdas com Dashbird , e eu estou amando isso. O meu ponto de exibição para você também é para você ver os logs do console das invocações da função Lambda. Eles mostrarão quando o Lambda está usando uma conexão de banco de dados nova ou existente. Veja como é o painel principal, onde vejo todos os meus Lambdas e suas estatísticas.

Depois de pressionar a função resto-api-dev-getAll Lambda, eu vou ser levado para uma tela com todas as estatísticas e logs para esta função particular.

Na parte inferior, você vê duas invocações da função getAll. Depois de pressionar o mais velho dos dois, isso me leva a outra página mostrando informações sobre essa invocação particular.

Como você pode ver, o console foi logado com => using new database connection e a solicitação real demorou cerca de 1,5 segundos.

Voltando e pressionando a outra invocação, podemos ver uma imagem diferente, mas ainda, por sorte, para nós, uma imagem diferente.

Uma vez que a mesma função Lambda foi invocada novamente, ela irá reutilizar a conexão existente. Isso pode ser visto claramente nos registros aqui.

Fim da linha

Que montanha-russa emocional. Você foi levado em uma viagem para criar uma API REST sem servidor com MongoDB. Eu tentei o meu melhor para transferir a experiência que eu reuni até hoje para mostrar a você a maneira preferida de criar uma API adequada. Muitas das técnicas que mostrei são o que eu uso em uma base diária. Use essas habilidades com sabedoria e divirta-se mais profundamente nas possibilidades da Arquitetura sem Servidor e de tudo que vem com ela.

Se você quiser dar uma olhada em todo o código que escrevemos acima, aqui está o repositório . Ou se você quiser ler meus artigos mais recentes, vá até aqui.

Últimas histórias escritas por Adnan Rahi? – Médio
Leia as últimas notícias escritas por Adnan Rahi? no Medium. Engenheiro de software @bookvar_co. Educador de codificação @ ACADEMY387 … medium.com

Espero que vocês e meninas tenham gostado de ler isso tanto quanto gostei de escrever.
Você acha que este tutorial será de ajuda para alguém? Não hesite em compartilhar. Se você gostou, esmague o clap abaixo para que outras pessoas vejam isso aqui em Medium.