Como criar um mecanismo de busca com Node.js + MongoDB (Mongoose)

CaptureEste post vem sendo pedido por alguns amigos tem algum tempo já. Isso porque mecanismos de busca tem sido motivo de muito estudo de minha parte desde 2010, quando estava me formando na faculdade e resolvi criar o Busca Acelerada, o primeiro mecanismo de busca que desenvolvi. De lá pra cá tive a oportunidade de desenvolver buscadores de legislação, de fofocas de famosos, de informações da construção civil e muito mais.

A ideia então é eu mostrar, rapidamente, como se cria um site básico de busca que, embora simples, já será muito superior à maioria dos buscadores que os desenvolvedores fazem baseados em SQL. Sim, porque o meu site de busca não usará SQL, mas sim NoSQL, MongoDB para ser mais exato. E para a performance ficar ainda melhor, ele será feito usando a dupla NodeJS + MongoDB que nasceu pra ficarem juntos!

Para conseguir acompanhar este post, você já deve conhecer NodeJS + MongoDB. Caso não conheça, sugiro começar com este tutorial aqui. Também é altamente recomendado que tenha lido esse meu outro post, sobre como criar mecanismos de busca.

Note que não vou ensinar aqui como se criam crawlers ou qualquer outro algoritmo de coleta de informações para popular seu mecanismo, conforme citado no post sobre mecanismo de busca. Considero aqui que você já tem uma massa de dados que deseja oferecer através de um site de busca. Pode ser uma base SQL tradicional, um XML, um Excel, você que sabe.

Caso realmente precise criar um crawler, leia este post aqui!

Com tudo isso em mente, vamos começar!

Veremos nesse artigo:

  1. Configurando o Projeto
  2. Configurando o Banco
  3. Preparando os dados
  4. Configurando o ORM
  5. Criando as views
  6. Programando a busca

Querendo algo mais “pesado” de MongoDB, sugiro este post aqui, focado nesta tecnologia de banco de dados.

Parte 1: Configurando o projeto

Baixe e instale o NodeJS na sua máquina. Crie uma pasta para seus projetos Node e vá até ela via linha de comando, digitando:

Isso irá criar toda a estrutura de pastas do nosso projeto searchengine usando Express (se o comando express não rolar é porque você tem de dar o ‘npm i -g express-generator’).

Agora instale as extensões do mongodb e do mongoose:

Volte ao prompt de comando, navegue até a pasta do projeto searchengine e mande instalar todas as dependências com o comando “npm install”.

Depois, vá na pasta views e dentro do arquivo error.ejs, cole o seguinte código HTML:

Os demais arquivos vamos mexer depois.

Parte 2: Configurando o banco

Aqui você tem duas opções: usar um Mongo em uma plataforma, como a mLab ou a Umbler, e outra é instalar e configurar tudo na unha. Você escolhe.

Opção 1: Solução na nuvem

Crie uma conta na Umbler e você já terá os créditos para gastar sem precisar desembolsar dinheiro neste teste e inclui hospedagem Node.js e Mongo facilmente. A mLab tem uma versão free também que dá conta, mas só nos datacenters americanos e você teria de ter uma conta em outra empresa que possua Node para ter a solução completa.

Na sua conta da Umbler, basta criar um site Node.js e na seção de bancos de dados, criar um banco MongoDB. Anote o host, usuário, senha, etc pra usar depois.

MongoDB
MongoDB

Pronto, você tem o seu banco ok!

Opção 2: Solução local

Baixe e instale o MongoDB (é apenas uma extração de pastas e arquivos, que sugiro que faça em C:/). Agora abra o prompt de comando, navegue até a pasta onde foi instalado o seu Mongo, geralmente em “c:\program files\mongodb\”, acesse a subpasta “server/3.2/bin” e dentro dela digite o comando (certificando-se que exista uma pasta data dentro de C:\mongodb):

Isso irá criar e deixar executando uma instância do MongoDB dentro da pasta data do mongodb. Não feche esse prompt para manter o Mongo rodando local.

Independente da opção escolhida

Agora abra outro prompt de comando (ou use alguma ferramenta de manipulação do MongoDB, como o Studio 3T) e navegue até a pasta bin do MongoDB novamente, digitando o comando “mongo” para iniciar o client do Mongo. Se o seu MongoDB é local, o comando será apenas mongo, no entanto, se for remoto, você vai se conectar da seguinte maneira:

Neste exemplo, meu servidor é tatooine.mongodb.umbler.com, a porta é 36947, meu banco se chama nomeBanco, meu usuário = usuario e minha senha = senha. Altere estas informações conforme a sua configuração!

Depois, chame o comando “use nomeBanco” para se conectar ao banco que usaremos nesse projeto (substituindo nomeBanco pelo nome do seu banco, aqui chamarei de searchengine). Deixe o prompt aberto, usaremos ele em breve para inserir alguns dados de exemplo em nosso banco do buscador.

Caso tenha gostado de usar o MongoDB e queira se aprofundar mais no assunto, recomendo o curso que criei e que você pode conhecer clicando no banner abaixo:

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

 

Parte 3: Preparando os dados

Você pode ter uma base SQL com os dados consolidados do seu negócio e usar o MongoDB apenas como índice e/ou cache de busca. Ou então você pode usar apenas o MongoDB como fonte de dados. Fica à seu critério.

Caso escolha usar SQL e MongoDB, você terá de ter algum mecanismo para mandar os dados que deseja que sejam indexados pelo seu buscador para o Mongo. Este post não cobre migração de dados (mongoimport é o cara aqui), então você deve fazer por sua conta e risco usando os meios que conhecer.

Caso escolha apenas usar o Mongo, você apenas terá de alterar as suas coleções pesquisáveis para incluir um campo com o índice invertido que vamos criar na sequência, com nosso buscador de exemplo.

Em ambos os casos, a sua informação “pesquisável” deve ser armazenada de uma maneira prática de ser pesquisada, o que neste exemplo simples chamaremos de tags. Cada palavra dentro das informações pesquisáveis do seu sistema deve ser transformada em uma tag, que geralmente é um texto todo em maiúsculo (ou minúsculo) e sem acentos ou caracteres especiais.

Por exemplo, se quero tornar pesquisável os nomes dos meus clientes, que no meu SQL estão como “Luiz Júnior”, eu devo normalizá-lo para as tags “LUIZ” e “JUNIOR”, separadas. Assim, quando pesquisarem por luiz, por junior, or luiz junior e por junior luiz, este cliente será encontrado.

Assim, cada registro na sua coleção do MongoDB terá um atributo contendo as suas tags, ou informações pesquisáveis, o que facilmente fazemos com um atributo do tipo array no Mongo. Como abaixo:

Para podermos fazer a busca depois usaremos uma query com um $in ou um $all, que são operadores do Mongo para pesquisar arrays de palavras (seus termos de busca) dentro de arrays de palavras (as tags).

Então, caso esteja migrando dados de um SQL para o Mongo, certifique-se de quebrar e normalizar as informações que deseja pesquisar dentro de um campo tags, como o acima, que será o nosso índice de pesquisa.

Para fins de exemplo, usaremos a massa de dados abaixo (apenas 2 registros) para pré-popular nosso banco com clientes (customers) que já possuem tags normalizadas como mencionado acima. Note que as tags de cada customer são um misto de seus nomes e profissões, o que você pode facilmente fazer com seus dados também.

O comando acima deve ser executado no console cliente do Mongo, logo após o “use searchengine”.

Obviamente existem técnicas de modelagem de banco para mecanismos de busca muito mais elaboradas que essa. Aqui estamos tratando todas as informações textualmente sem classificação do que é cada uma, sem se importar com a ordem ou peso delas, etc. Mas a partir daqui você pode fazer as suas próprias pesquisas para melhorar nosso algoritmo.

Mais pra frente, quando fizermos as nossas pesquisas, vamos fazê-las sempre buscando no campo tags, ao invés de ir nos atributos do documento. Até porque nosso buscador terá apenas um campo de busca, assim como o Google, como veremos adiante.

Mas e a performance disso?

Para resolver este problema vamos criar um índice nesse campo no MongoDB. Mas não é qualquer índice, mas sim um índice multi-valorado pois o campo tags é um array de elementos. O Mongo organiza campos multi-valorados em índices invertidos, que são exatamente um dos melhores tipos de índices básicos que podemos querer em um mecanismo de busca simples como o nosso. Eu já mencionei sobre índices invertidos no post sobre Como criar um mecanismo de busca.

O comando acima deve ser executado no console cliente do Mongo, logo após o “use searchengine”. Todos os customers inseridos a partir de então respeitarão essa regra do índice no campo tags.

Para verificar se funcionou o nosso índice, teste no console cliente do Mongo consultas como essa que traz todos os clientes que possuam a tag LUIZ (isso funciona para lógica OR também, pois recebe um array de possibilidades):

Ou esse que traz todos com as tags LUIZ e JUNIOR (aqui temos lógica AND):

Parte 4: Configurando o ORM

Aqui usaremos o Mongoose, o mais profissional e eficiente ORM para NodeJS + MongoDB na época em que escrevo este post. Fiz testes com um concorrente, o Monk, e a diferença era de 50% a mais de performance, então fique com o Mongoose. Caso não goste de ORMs, neste outro tutorial ensino como usar o MongoDB com o driver nativo.

Conforme definimos na parte 1 deste tutorial, o Mongoose foi instalado como sendo uma das dependências em nosso packages.json, então basta utilizarmos ele em nossos códigos JS.

Crie na raiz do seu projeto um arquivo db.js e dentro coloque a conexão do Mongoose com seu MongoDB, mais o esquema da sua coleção que será consultada (troque a string de conexão apropriadamente).

Note que definimos o schema da nossa coleção customers, incluindo o campo tags como sendo um array de elementos, como já vimos na parte 3 deste tutorial.

Parte 5: Criando as views

Agora vamos criar as views que vamos utilizar: a de pesquisa e a de resultados de pesquisa (chamada de SERP pelos especialistas: Search Engine Results Page). Na verdade vamos fazer as duas em uma, por pura preguiça deste que vos escreve. 😉

Dentro da pasta views do seu projeto, abra index.ejs e cole o seguinte código HTML dentro dele:

Essa é uma página de busca bem simples, com um formulário contendo um campo e um botão de pesquisar. Quando o formulário é submetido, enviamos o usuário para a página de resultados, que vamos criar na sequência.

Salve o arquivo, reinicie seu servidor NodeJS (derrube-o com Ctrl+C se estiver executando e depois inicie-o com npm start a partir da pasta do projeto searchengine).

Capture

O print está meio tosco pois tudo está centralizado. 🙂

Se você pesquisar alguma coisa, como a palavra teste da foto, verá que não vai funcionar, vai dar erro 404, porque ainda não criamos a página de resultado, nem a rota para ela. Na verdade usaremos a mesma página, com algumas modificações.

Parte 6: Programando a busca

Inclua o seguinte código que mistura HTML com JS (característica da view engine EJS que estamos utilizando) logo após seu formulário de busca, na index.ejs:

Esse código vai permitir que, na mesma página de busca, a gente liste os resultados logo abaixo, quando houverem. Quando não existirem resultados, uma mensagem informará adequadamente.

Note que incluímos aí uma série de elementos que vamos ter que programar agora, para que funcionem, entre eles as variáveis results, list e search, que devem ser passadas através da rota que levará o usuário até esta página.

Primeiro, vamos modificar a rota default que leva até a index com a caixa de busca para que ela retorne a variável results como false, indicando que não há resultado a serem exibidos e que a lista de resultados não deve ser exibida pois é um acesso à home.

Substitua o código original da rota default por este. Isso garantirá que a nossa index.ejs continue funcionando mesmo após nossas últimas adições.

Agora, adicione uma nova rota, que atenderá às requisições /search que são feitas quando se clica no botão de busca da index.

Aqui nós pegamos a variável de querystring chamada query e colocamos ela toda em maiúsculas e damos um split pelos espaços, para transformar os termos de busca em um array de termos. O ideal é criar alguma rotina de normalização dos termos de busca, para fazer coisas mais avançadas que essa como remover acentos, etc, mais deixo ao seu critério.

Uma vez com os termos de busca OK, carregamos a variável db com os dados do banco, carregamos o model de customers e damos um find por documentos que possuam as tags que estamos buscando. Nesse caso estou usando um $all, que faz a lógica AND, mas você pode ajustar facilmente por um $in, para fazer a lógica OR ou ainda fazer uma mescla através de análise da pesquisa realizada (tipo o que o Google faz quando digitamos com aspas – AND – ou sem aspas – OR).

O resultado da pesquisa é retornado em um objeto contendo results:true (foi realizada uma pesquisa), search (os termos pesquisados) e list (os documentos retornados). Esse objeto será usado pela lógica anterior que colocamos no EJS que itera sobre os elementos e os renderiza como itens de uma lista não ordenada.

Salve todos os arquivos que não estejam salvos, reinicie o seu servidor Node e mande executar novamente. Você irá entrar na tela index normal, mas quando pesquisar por algum termo que exista no seu banco, verá uma tela de resultados como essa:

Capture

Ou, caso tenha pesquisado por um termo que não existe, verá algo como:

Capture

Claro que você pode fazer muitas modificações nos seus resultados de pesquisa. Você pode querer jogá-los em uma página separada, com um layout mais profissional. Pode querer colocar links neles que levarão o usuário para páginas com detalhes sobre os clientes. Pode querer implementar algum tipo de autocomplete na caixa de busca, usando o Typeahead do Bootstrap. Pode implementar algum mecanismo para sinônimos, plurais, etc para tornar sua busca mais inteligente.

Há milhares de coisas que você pode fazer e eu poderia escrever um ebook sobre isso. Se tivesse tempo no momento. 😀

De qualquer maneira, acho que já consegui dar uma luz à quem nunca criou um buscador antes. Ou quem criou apenas usando LIKE % do SQL tradicional. :/

Caso queira transformar seu algoritmo de busca em uma API, recomendo fortemente dar uma olhada sobre como criar uma API com NodeJS.

Caso vá colocar esse projeto em produção e esteja enfrentando problemas, dê uma olhada nesse post sobre como fazer deploy em servidores Windows.

Depois que colocar ele em produção, visando obter muitas visitas vindas do Google, sugiro ler esse meu artigo aqui sobre SEO para mecanismos de busca.

Eu ministrei recentemente uma palestra sobre este assunto, cujos slides estão abaixo (o código está ligeiramente diferente):

Um abraço, e até a próxima!

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

Como criar uma Web API com Node.js (Express + MongoDB + Mongoose)

node-js-mongodb

Atualizado em 20/10/2019!

Node.js é meu mais novo framework gratuito favorito para criar meus empreendimentos digitais. Não apenas porque eu já tenho alguns anos com experiência em Javascript e poder utilizar ele no frontend e no backend é bem tentador. Não apenas porque ele roda sobre Linux o que reduz o meu custo com licenciamento de servidor para zero. Não apenas porque ele é muito mais leve do que .NET, a plataforma que comumente eu utilizava para todos os meus projetos, permitindo o dobro de usuários com os mesmos recursos.

É por tudo isso e muito mais.

Não me entenda mal, eu adoro .NET e especificamente o C#. Ainda uso bastante C# para construção de sistemas. Mas coisas como reduzir custos de servidor de U$120 para U$15 me chama muito a atenção nessa nova plataforma…

Nesse post vou lhe ensinar como criar uma API usando Node.js, MongoDB, Express e Mongoose. Não sou nenhum especialista no assunto, mas tenho a experiência de alguns projetos rodando com essa configuração como o BuildIn e o SóFamosos. Em breve o Busca Acelerada deve ser migrado para esta plataforma também. Se preferir, tenho um outro que ensina como fazer uma API Node.js com MySQL.

Se você não conhece nada de Node.js, recomendo dar uma olhada nesse post primeiro, que vai lhe ajudar com os passos iniciais, que eu não serei tão didático aqui com a primeira parte. Se não conhece o protocolo HTTP, essencial para desenvolvimento web, leia este post. Já se você não gosta de ORMs e quiser aprender a mexer com o MongoDB nativamente, use este post primeiro.

Neste tutorial veremos:

  1. Configurando o projeto
  2. Configurando o banco
  3. Configurando o Mongoose
  4. GET de um cliente (consulta)
  5. POST de um cliente (cadastro)
  6. PUT de um cliente (edição)
  7. DELETE de um cliente (exclusão)

Querendo algo mais “pesado” de MongoDB, sugiro este post aqui, focado nesta tecnologia de banco de dados.

Parte 1: Configurando o projeto

Primeiro, caso ainda não tenha feito, baixe e instale o NodeJS no site oficial.

Segundo, crie uma pasta para seus projetos node. Abra o prompt de comando e acesse o diretório dos seus projetos Nodes, criado logo antes. Rode o comando abaixo para criar um projeto Express dentro dela, com o nome de apitest:

Isso irá criar toda a estrutura básica de uma aplicação Express, incluindo rotas default, o arquivo app.js com o coração da aplicação, usando a view engine EJS e com suporte a Git (opcional).

Terceiro, rode o comando abaixo para adicionar algumas dependências novas no package.json:

Agora que suas dependências estão prontas, rode o comando abaixo para instalar todas elas no seu projeto:

Quarto passo, sua aplicação Express deve estar funcionando agora, rode o comando abaixo para executá-la e se certificar que fez tudo correto até aqui.

Acesse localhost:3000 no navegador e verá se a index aparece corretamente.

Capture

Voilá, funcionando!

Parte 2: Configurando o banco

Caso você já tenha um banco MongoDB pronto, ignore essa parte e pule para a parte 3. Você pode facilmente usar um MongoDB hospedado na Umbler, além de hospedar a sua própria hospedagem Node.js lá também, usando os créditos gratuitos para seus testes e depois pagando muito pouco.

Por que MongoDB? Porque é um dos bancos com maior fit com o NodeJS. Dependendo da sua demanda, outros NoSQL como Influx, Rethink e Redis podem lhe ser bem úteis. Outras alternativas são os bancos relacionais mais tradicionais, como o MySQL.

Vou usar linha de comando aqui. Caso prefira uma ferramenta visual, sugiro o Studio 3T que é gratuito e eu uso bastante.

Primeiro passo, se ainda não tem o MongoDB na sua máquina, baixe-o no site oficial. Instale/extraia os arquivos para seu C:\MongoDB ou qualquer caminho que preferir.

Segundo passo, primeiro crie uma pasta data dentro da pasta da sua api. Depois abra o prompt de comando e navegue até a pasta do seu MongoDB, dentro dela terá uma pasta server/versão/bin e dentro dela você executará a seguinte linha de comando, que iniciará o servidor Mongo dentro da API:

Se aparecer a mensagem de “waiting connections”, está tudo ok.

Terceiro passo, vamos adicionar alguns registros em nosso banco para não iniciar com ele zerado. Neste exemplo irei inserir alguns clientes no banco, que sempre é um bom exemplo comercial. Para isso, abra outro prompt de comando e navegue até a pasta do seu MongoDB, dentro dela terá uma pasta server/versão/bin e dentro dela você executará a seguinte linha de comando, que iniciará o cliente Mongo:

Uma vez com o cliente aberto, digite o seguinte comando para se conectar no nosso banco da API:

E na sequência vamos inserir um array de registros de clientes:

Se quiser testar pra ver se funcionou, basta dar um db.customers.find().pretty() e serão listados todos os clientes cadastrados no banco.

Com isso temos todo o ambiente pronto e configurado, agora vamos programar!

Caso tenha gostado de mexer com MongoDB e queira se aprofundar mais no assunto, sugiro o meu curso abaixo:

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

 

Parte 3: Configurando o Mongoose

Alguns tutoriais na Internet ensinam usando o ORM Monk. O Monk é legal, super fácil de utilizar e tenho grande apreço por ele, mas…ele é uma m**** quando o assunto é desempenho (50% a menos de desempenho nos testes que fiz). Por isso, vamos usar o Mongoose aqui, que é a solução de ORM mais profissional para usar MongoDB com NodeJ.js.

Primeiro passo, crie um arquivo db.js na raiz do seu projeto apitest. Dentro dele, cole o seguinte código, que explicarei na sequência:

Aqui eu criei um objeto Mongoose, fiz a conexão com nosso banco que está rodando local e defini o schema da coleção de clientes no banco de dados, usando o mesmo nome que já tinha usado na parte 2 (customers). Por fim, exportei um objeto contendo o Mongoose e o schema, para uso posterior.

Segundo passo, vamos testar. Para fazer isso, vamos fazer o método mais elementar e básico da API: o GET por todos os clientes da base. Mais pra frente implementaremos elementos importantes como paginação, mas por ora, vamos retornar todos. Abra seu arquivo index.js dentro da pasta routes do seu projeto. Coloque o seguinte código logo acima do module.exports:

Esse código basicamente pega todas requisições GET para a URL localhost:3000/customers e retorna todos os clientes cadastrados no banco no formato JSON, diretamente no corpo da resposta, que é o esperado para uma API. Salve esse arquivo e reinicie o servidor NodeJS, para que as alterações surtam efeito.

Terceiro passo, vamos pro navegador testar: acesse localhost:3000/customers e você deve ver o seguinte resultado:

Capture

Aqui eu cortei parte da resposta, mas é apenas um array JSON com os elementos existentes no banco de dados. Isso mostra que tudo está funcionando por enquanto.

Com esse conhecimento você já é capaz de entender como tudo funcionará daqui pra frente, adicionando verbos HTTP ao endpoint customers e executando as consultas e comandos apropriados no banco de dados e retornando JSON.

Caso já queira colocar isso que você fez em um servidor Windows, sugiro ler este post aqui. Se quiser hospedar na Umbler (você vai ter de criar o banco MongoDB lá também), pode fazê-lo via Git com instruções dentro do painel da Umbler, após criar o site Node.

Parte 4: GET de um cliente

Agora vamos alterar nosso código para retornar apenas um cliente, algo bem comum em APIs, uma vez que nem sempre você vai querer retornar todos os elementos de uma coleção do banco.

Para isso, basta criarmos uma nova rota /customers para também aceitar um ID logo após seu path, algo como /customers/123-abc-456-def (lembrando que no MongoDB usamos guids alfanuméricos). O código abaixo mostra como seria essa nova rota:

Note o uso de :id indicando que o parâmetro logo após /customers será o ID do mesmo. Note também o uso de um filtro em nosso find, baseado no _id do documento.

Para conseguir testar, primeiro você terá de descobrir o _id de um cliente que já esteja no banco. Para isso, use o Studio 3T (antigo Mongo Chef) ou a própria linha de comando “mongo”, que fica dentro da pasta bin do MongoDB, executando um db.customers.find().pretty() e copiando o _id de qualquer um. Caso você não saiba como copiar texto do console, basta clicar com o botão direito, escolher Mark, selecionar o texto que quer e clicar com o botão direito do mouse sobre ele. Pronto está copiado, basta colar onde quiser.

Salve o arquivo, reinicie seu servidor Node e o resultado de uma pesquisa com ID é o abaixo:

Capture

Nem perca tempo querendo copiar o ID do meu cliente, ele nunca se repete.

Parte 5: POST de um cliente

O próximo passo é criarmos uma rota que permita adicionar novos clientes em nossa coleção. Segundo a especificação HTTP, o verbo POST é usado quando queremos adicionar novos elementos, então é isso que faremos, uma rota que manipule o POST em nossa API, como no exemplo abaixo.

Note que este código já começa diferente dos demais, com router.post ao invés de router.get, indicando que está rota tratará POSTs no endpoint /customers. Na sequência, carregamos o objeto db para pegar o model customers do Mongoose, criarmos um novo customer com o name e o email que vieram no body da requisição (incluindo aqui requisições com body em JSON) e depois mandamos ele salvar no banco.

Nosso save também está um pouco diferente do exemplo do post de introdução, pois aqui estamos tratando o caso de dar algum erro. Neste caso enviamos um código HTTP 500 ao consumidor da API, com um JSON contendo a mensagem de erro. De outra maneira, em caso de sucesso, devolvemos o objeto customer que acabou de ser criado, incluindo o _id que recebeu.

Salve seu arquivo e reinicie o servidor Node. Agora vamos testar!

Mas como testar um POST se no navegador só conseguimos fazer GETs?

Usando uma ferramenta muito bacana chamada POSTMAN, que usaremos não apenas para esta parte do tutorial, mas para outras também. Baixe e instale o POSTMAN no seu Google Chrome e execute-o, ele é apenas um forjador de requisições bem útil (outra opção é o Fiddler). Você verá a tela abaixo:

Capture

Note que no primeiro select eu escolhi o verbo POST e na caixa de endereço digitei localhost:3000/customers, que é o endpoint da nossa API. Depois temos as abas Authorization (para adicionarmos autenticação futuramente), Headers e Body.

Em Headers, adicione a chave-valor Content-type (chave) com “application/json” (sem aspas, valor), indicando que vamos POSTar JSON na API. Já em Body, marque a opção raw (crú) e digite um objeto JSON que represente os dados de um customer no campo logo abaixo. Segue um exemplo para você copiar e colar:

Agora sim podemos testar!

Considerando que você já esteja com seu servidor atualizado e rodando, clique no enorme botão Send do POSTMAN e sua requisição será enviada. Quando isso acontece, o POSTMAN exibe em uma área logo abaixo da requisição, a resposta (response) da requisição, como abaixo:

Capture

Note que é mostrado o corpo da resposta (nesse caso o customer que enviamos, incluindo o _id) e o status da mesma (nesse caso um 200 OK).

Mas será que funcionou mesmo?

Basta digitarmos localhost:3000/customers em nosso navegador (ou construir uma requisição GET no POSTMAN) e veremos que nosso novo customer está lá!

Capture

Parte 6: PUT de um cliente

Agora que já podemos consultar todos clientes, consultar um cliente e salvar um novo cliente, é hora de permitirmos que os usuários de nossa API atualizem os dados dos clientes.

A especificação para APIs HTTP REST define que nosso endpoint deve esperar receber o id do objeto que queremos atualizar na URL, no formato /customers/id, enquanto que no corpo da requisição devemos enviar o novo objeto que vai substituir o original na coleção.

Sendo assim, vamos configurar mais uma rota em nosso arquivo /routes/index.js:

Neste exemplo estamos configurando uma rota PUT para /customers/id. O processo inicial do algoritmo não é muito diferente dos demais, onde carregamos o objeto db, o model Customer e com ele chamamos o método findOneAndUpdate que, baseado na query {_id: req.params.id} irá alterar o objeto com o req.body passado (que é o JSON que enviaremos na requisição PUT com os valores atualizados do customer).

O próximo parâmetro, upsert:true, indica que se o customer não existir, ele será criado. Fica a seu critério manter esta configuração assim ou não. Já a nossa função de callback é a de sempre: retornará o erro em caso de falha ou o objeto JSON que foi salvo se tudo der certo.

Salve e reinicie o seu servidor Node para podermos testar.

Para testar, primeiro pegue o _id de algum customer que irá ser atualizado. Você pode fazer isso fazendo um GET em todos eles no navegador, no POSTMAN ou mesmo via linha de comando “mongo” e executando uma query db.customers.find().pretty(). Você que escolhe.

Com o _id em mãos, abra o POSTMAN novamente (ou melhor, não feche-o) e construa a seguinte configuração:

  • verbo HTTP: PUT
  • URL: localhost:3000/customers/{seu_id} (troque seu_id pelo ID do seu objeto que irá atualizar)
  • Headers: adicione “Content-Type” e “application/json” na primeira linha
  • Body: selecione “raw” e cole o seu objeto JSON, sem o _id, com os dados que serão atualizados, como abaixo, onde mudei o nome do customer:

A sua configuração do POSTMAN deve se parecer com a abaixo:

Capture

Note que não adianta copiar o ID que eu coloquei na URL pois ele não se repete!

Clique no botão Send do POSTMAN e ele enviará esse PUT para nossa API, recebendo como retorno (se tudo der certo) o mesmo JSON que enviamos, que nem vale a pena colocar o print aqui.

Para ver se deu certo, basta fazermos um GET no navegador ou POSTMAN (ou ainda via linha de comando) para ver que o nome do customer de exemplo, que era luiztools, agora está mostrando “luiz fernando”.

Capture

Update: check!

Parte 7: DELETE de um cliente

E para finalizar o CRUD da nossa API, vamos criar uma rota que espere um verbo DELETE com o id do customer a ser excluído na URL. Fácil, fácil!

Essa nossa nova e última rota trata requisições com o verbo HTTP DELETE no endpoint /customers/id. Para excluir o documento correspondente da nossa coleção basta darmos um find por _id usando o id que veio na URL e chamando a função remove logo em seguida, que removerá o documento que for retornado pelo find. O conteúdo do callback do remove dispensa comentários.

Salve o arquivo e reinicie o servidor Node para podermos testar usando o POSTMAN.

Mas antes, como é de praxe, você deve obter o ID de algum customer que você deseje excluir. Vai lá, eu espero.

Voltando ao POSTMAN, mude o verbo HTTP para DELETE, a URL para localhost:3000/customers/{seu_id} (troque pelo id do customer que quer excluir) e limpe qualquer coisa que tenha no seu body.

Clique em Send e se tudo der certo você verá um success: true como resposta no POSTMAN. Para se certificar que funcionou, faça um GET no endpoint raiz /customers e você verá que um customer não existe mais. No meu caso, o customer luiztools/luiz fernando:

Capture

E com isso finalizamos a nossa API em NodeJS!

Quando quiser fazer deploy dessa API em produção, dê uma olhada nesse outro post se estiver usando Windows ou use a Umbler, provedor que uso para minhas aplicações Node e PHP.

Se quiser colocar autenticação na sua API, você pode adaptar este tutorial aqui, se quiser colocar validação dos inputs leia esse e se quiser colocar autorização, este sobre JWT vai lhe ajudar.

Existe uma série de artigos super bacana aqui no blog que ensina como estruturar uma arquitetura de microserviços, toda baseada em webapis, pode ser o seu próximo passo com Node e Mongo.

Qualquer coisa que precisar, chama aí nos comentários.

Até a próxima!

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

Por que aprender Node.js? 8 Casos reais!

nodejs-logo

Atualizado em 21/06/17 com mais cases!

Depois de uma década desenvolvendo principalmente em Java e C#, recentemente minha atenção se voltou para Node.js. Isso tem chamado a atenção de pessoas próximas à mim que me perguntam porque não troquei Java e C# por linguagens mais “legais” como Ruby e Python.

Como alguém que sempre trabalhou com linguagens fortemente tipadas, orientadas à objeto e em projetos com arquiteturas bem definidas, eu gosto de linguagens “chatas”. Não estou à procura de “zoeira” na minha vida de programador. Eu estou à procura de eficiência.

Eu quero reduzir meus custos com infraestrutura. Eu quero aumentar o desempenho dos meus projetos. Eu quero programar mais rápido.

Node.js me proporciona tudo isso em uma escala sem precedentes. E quanto mais aprendo sobre a plataforma, mais me interesso por ela.

Mas uma dúvida sempre ficava em minha cabeça: será que tem alguém “grande”, que use Node.js em projetos de verdade?

Fui atrás de resposta e embora seja uma plataforma relativamente nova, ela já está sendo utilizada por várias empresas da Fortune 500 e gigantes da tecnologia, principalmente pelas características que citei antes: escalabilidade, velocidade de entrega e performance excepcional. Groupon, LinkedIn, Walmart, PayPal – são apenas algumas empresas bem sucedidas no uso de Node.js.

Os cases deste artigo são:

  1. Groupon
  2. LinkedIn
  3. Walmart
  4. PayPal
  5. Dow Jones
  6. Uber
  7. GoDaddy
  8. Netflix
  9. Conclusões

Vamos lá!

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

Groupon

 

Em 2013 o Groupon trocou sua tecnologia de backend de Ruby on Rails para Node.js. O engenheiro Adam Geitgey comenta sobre essa mudança nesse post, e eu transcrevo uma parte aqui:

“Estávamos buscando por uma solução para um problema específico – manipulação eficiente de múltiplas requisições HTTP, fazendo chamadas de API paralelas para servir cada uma dessas requisições e renderizando os resultados em HTML. Também queríamos algo em que pudéssemos confiar.”

A troca para Node.js lhes entregou exatamente isso. Groupon notou uma melhora significativa no tempo de carregamento das páginas de todo o site, na faixa de 50%. Não só isso, mas os times de desenvolvedores passaram a entregar features mais rápido também.

LinkedIn

Quando a maior rede social profissional do mundo relançou seu app mobile em 2011 usando Node.js como backend, eles conseguiram melhorar a velocidade do seu sistema em 20x ao mesmo tempo em que reduziram o número de servidores em 90%.

O líder de desenvolvimento mobile Kiran Prasada, em entrevista ao VentureBeat, disse que “Foi rápido acima de qualquer padrão”. “Eu já trabalhei em empresas grandes e startups como Yahoo, e yeah, era muito rápido.”

Walmart

O maior varejista do mundo levou o uso de Node.js a outra dimensão quando decidiram adotar a plataforma para uso na Black Friday, o maior dia de vendas do ano. E a escolha se pagou: na Black Friday, os servidores do Walmart não chegaram a usar mais de 1% de suas CPUs, a despeito do fato de que suportam 200 milhões de usuários naquele dia.

“Node nos permitiu…escalar muito bem,” conforme dito por Dion Almaer, VP do Walmart para arquitetura mobile. “Ele é perfeito para o que estamos fazendo em mobile.”

PayPal

PayPal é outra grande empresa que está colhendo os benefícios do Node. Sua primeira aplicação Node.js foi uma reescrita de sua página de overview da conta – “uma das mais visitadas do site”, segundo Jeff Harrell do PayPal. Querendo testar o Node, mas sem se arriscar demais, eles decidiram por construir a aplicação em Node.js e em Java, lado a lado, para ver qual teria a melhor performance.

E nesse teste lado-a-lado, Node.js venceu. O time que usou Node desenvolveu duas vezes mais rápido, com menos pessoas, com 33% menos linhas de código e com 40% menos arquivos. Além disso temos a performance. Node conseguiu atender o dobro de usuários por segundo do que o Java, com uma média de 35% mais velocidade na entrega das requisições.

Segue um vídeo de uma das apresentações que o PayPal fez de como estão usando Node em seus projetos:


Dow Jones

Em 2010 a editora Dow Jones (responsável pelo jornal financeiro mais famoso do mundo, o The Wall Street Journal, com 2.1 milhões de cópias vendidas por dia) já usava Javascript. De acordo com Scott Rahner, líder de desenvolvimento da empresa, o time de desenvolvedores começou a usar Node.js em produção pela primeira vez em 2011, durante uma aplicação experimental de leitura do Facebook, o Wall Street Journal Social. Eles experimentaram grande performance na aplicação e no processo de desenvolvimento, que foi concluído em poucas semanas. O CTO ficou espantado com o sucesso obtido com Node.js e convenceu a diretoria a apoiar a tecnologia o que culminou com o Node.js sendo a tecnologia primária da empresa, sendo atualmente utilizada para a maioria dos projetos, especialmente os produtos para os consumidores.

Com as palavras, Scott Rahner da Dow Jones (em uma tradução livre):

“Quando você pensa em Javascript, não há nenhuma tecnologia igual. Algo que você pode fazer deploy em qualquer plataforma, não importa se é Linux, Windows, Heroku, AWS, Digital Ocean, etc… É mais famosa entre os engenheiros do que qualquer outra linguagem. Obviamente combina com as exigências de performance das aplicações de hoje em dia. Combina perfeitamente.”

Uber

Na NodeConf que aconteceu em 2015, Tom Croucher, Engenheiro Sênior na Uber, compartilhou o seguinte relato (tradução livre):

“A coisa que eu mais gosto no Node é o quanto de poder que eu pessoalmente passei a ter com ele. A facilidade com a qual eu consigo fazer coisas com Node amplificou o meu poder enquanto desenvolvedor.”

O Uber começou a usar Node ainda na versão 0.8 e desde a versão 0.10 que eles relatam que a plataforma é super estável e funciona muito bem. O core dos sistemas dessa empresa que na época do relato valia 15 bilhões de dólares é escrito em Node, mais especificamente seus confiáveis sistemas distribuídos e suas bases de dados geoespaciais.

Segue o vídeo com a referência original e neste post o mesmo Tom Croucher fala do uso de Node e de Go, junto de Python, em toda aplicação do Uber:


GoDaddy

Dessa vez quem fala bem de Node é Stephen Comissio, desenvolvedor sênior da GoDaddy, uma das maiores empresas de hospedagens de site e registro de domínio do mundo.

Stephen, agora ex-desenvolvedor .NET, conta que há alguns anos atrás a GoDaddy empregava alguns dos mais experientes desenvolvedores Java e .NET do mercado. Eles queriam iniciar uma mudança cultural na empresa e pensaram que começar a prototipar aplicações em Node.js, lá atrás em 2013, foi um primeiro passo rumo a uma cultura mais ágil. Até então, o front-end da GoDaddy sempre confiou no Javascript e em aplicações single-page (SPA), mas o backend rodava com .NET. Para aumentar sua capacidade de atender requisições em uma de suas aplicações, a empresa decidiu mudar inteiramente seu backend para uma infraestrutura baseada em Node.js.

Durante o anúncio chamado ‘Puppet Master’ durante o SuperBowl de 2014, a GoDaddy enfrentou o seu maior desafio de escala. Eles tinham como meta que 100 milhões de pessoas visitassem um site em questão. A infraestrutura inteira da GoDaddy, naquele momento, conseguia lidar com 13 mil requisições por segundo, com um tempo de resposta médio de 87ms. Mas isto não era o bastante e eles tiveram que pensar em como melhorar ambas métricas, pois estimava-se que apenas um site relacionado ao SuperBowl receberia 10.000 requisições por segundo. Para suportar essa carga o site teve de ser migrado para um cluster próprio de 12 servidores e felizmente eles conseguiram fazer a tempo.

De acordo com Stephen, agora a GoDaddy suporta essa mesma carga com apenas 10% do hardware desde que migraram de .NET para Node.js. Isso significa menos servidores para gerenciar. Eles hoje estão aptos a servir 1.7 milhões de requisições por mês e sobreviveram a diversos ataques DDOS com impacto quase nulo usando Node.js.

O uso da tecnologia também representou um boom para a GoDaddy em termos de aquisição de talentos.

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

Netflix

 

A diretora de engenharia de front-end do Netflix, Kim Trott, contou a história do uso da plataforma na Netflix no último Node Summit em Portland.

A história começou em 2013 quando o Netflix não usava Node.js em produção. Eles tinham um grande sistema legado com um tempo de inicialização de 40 minutos, monolítico, builds demorados e máquinas de desenvolvimento enormes. Isto afetava a habilidade de serem mais produtivos e inovarem mais rapidamente. Eles até mesmo não conseguiam construir testes A/B eficientemente, o que é algo crucial uma vez que o Netflix constantemente roda diferentes versões das interfaces para fazer testes, centenas delas simultaneamente na verdade.

Para eles, estava impossível continuar nessa situação, cheios de retrabalhos e tudo mais, principalmente tendo de escrever um código completamente diferente para o front-end e para o backend. Eles usavam Java no servidor e Javascript no cliente. Eles tinham duas maneiras diferentes de depurar, acessar dados e renderizar, e estava ficando muito difícil de continuar trabalhando nesse ambiente. A contratação de profissionais experientes também estava sendo um problema. No fim das contas, eles não estavam se movendo tão rapidamente quanto precisavam para manter o negócio inovador.

Em um primeiro momento, eles estavam simplesmente buscando uma maneira simples de renderização para sua camada de front-end, mais especificamente fazer o roteamento correto das páginas, carregamento de templates e mescla de dados junto aos templates. Netflix também queria transformar o site em um Single Page Application ao invés de ficar renderizando todas as páginas do início ao fim.

Netflix escolheu Node.js uma vez que queria uma linguagem comum para escrever esse mesmo código já existente e de uma maneira que pudessem rodar onde quisessem. Isto ajudou muito os desenvolvedores que estavam constantemente ocupados trocando de contexto entre Java e Javascript toda hora.

Agora Netflix roda de maneira análoga a um SPA e com uma experiência de usuário muito mais rica, sendo que o Node.js é usado em todas as partes do site. Mais que 30% do time do Netflix trabalha com Node em produção e eles dizem que “você vai de 0 a 100 com Node muito rápido, você consegue fazer as coisas funcionarem rapidamente”.

Segue o vídeo com a referência:


Conclusões

Existem outras empresas que não divulgam tão publicamente seu apreço por esta tecnologia, como Google, Yahoo e Mozilla. Outras, como a Microsoft, que escreveu sua ferramenta de CLI do Azure em Node, tem apoiado, e muito, a Node Foundation.

Esses relatos, entre tantos outros que existem pela Internet, me fazem crer que é uma ótima opção de linguagem a se ter no rol de tecnologias dos programadores modernos. Empresas brasileiras que vem crescendo rápido, como a 4all, também estão utilizando Node e mesmo em meus projetos pessoais tenho aprendido a extrair cada vez mais dessa tecnologia.

Em um projeto recente, estimo que os ganhos de trocar C# por Node.js como tecnologia de backend vai me permitir reduzir os custos com datacenter em 75%, uma vez que 1) Node vai atender o dobro de usuários e 2) vou poder rodar ele em Linux sem receios e sem gambiarras.

Isso é eficiência.

Quer aprender hoje como programar em Node.js? Dá uma olhada nesses posts aqui:

e nesse vídeo que eu fiz recentemente:

De nada! 😉

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