Utilizando Node.js para o controle de hardware pela WEB através do protocolo Firmata

Neste artigo falarei sobre uma aplicação muito interessante que pode ser feita utilizando-se Node.js: o controle de hardware pela WEB. A aplicação que escolhi foi o controle do estado de diversos leds conectados a um Arduino, com o qual o servidor Node.js se comunicará. É uma aplicação extremamente simples do ponto de vista do hardware, mas que servirá para ilustrar os conceitos necessários para a criação de aplicações mais complexas. O código-fonte completo da aplicação pode ser baixado do repositório no GItHub.

A Aplicação

Primeiramente, descreverei em detalhes a aplicação que será desenvolvida. Ela consistirá de dois leds, que poderão ser acendidos ou apagados pelo usuário através de uma interface WEB. Além disso, o usuário poderá monitorar o estado desses leds a qualquer momento. A mesma aplicação poderá ser utilizada por diversas pessoas, e se um outro usuário alterar o estado de um dos leds através de outra instância da aplicação, os demais usuários serão informados disso em tempo real.

A aplicação é dividida em três partes distintas:

  • Interface do Usuário – Exibe o estado dos dois leds, e permite que esse estado seja modificado. O estado dos leds é mantido atualizado com o estado físico dos mesmos. Essa camada se comunica diretamente com o servidor Node.js;
  • Servidor Node.js – Recebe as solicitações de alteração de estado dos leds, e as repassa ao Arduino. Também é responsável por avisar à camada de interface das mudanças ocorridas no estado dos leds em tempo real. Essa camada se comunica tanto com a interface quanto com a camada de Hardware;
  • Hardware – Consiste dos dois leds mais o Arduino.

A comunicação entre a interface do usuário e o servidor Node.js será feita através da biblioteca http://socket.io, e a comunicação do servidor com o Arduino será feita de maneira serial. Cada uma dessas três partes serão descritas a seguir, de maneira independente.

Interface do Usuário

A interface é bastante simples. Cada um dos leds é representado um ícone, que pode estar em preto (led apagado) ou amarelo (led aceso). Além disso, há dois botões de ação. Se um led estiver aceso, e o botão correspondente a ele for acionado, esse led será apagado; caso contrário, ele será aceso. Os nomes dos leds são referentes aos pinos do Arduino aos quais eles estão conectados fisicamente.

Interface do usuário formada por dois leds, cada um deles com um botão de ação associado.

Para a geração do HTML da página, optei por utilizar a linguagem de template jade. É uma linguagem bastante simples, que facilita a geração do HTML através de uma linguagem mais limpa, e que possui uma série de funcionalidades. Essas funcionalidades não serão detalhadas, mas o leitor que sentir necessidade é convidado a ler a documentação oficial. O código abaixo gera todo o HTML da interface.

O css presente em style.css é bastante simples, então não vou adicioná-lo ao artigo para não deixá-lo desnecessariamente comprido.

Agora, descreverei o código javascript que será responsável por fazer a comunicação entre o navegador e o servidor Node.js. Essa comunicação será feita através da biblioteca socket.io. Ela permite que uma conexão seja mantida aberta entre as duas partes da aplicação, de modo que qualquer uma delas pode enviar uma mensagem para a outra a qualquer momento.

Essa conexão é estabelecida através do código abaixo.

Nesse código, localhost é o endereço do servidor node.js, e 5555 é a porta através da qual as mensagens serão trocadas. Agora, quando um dos botões for pressionado, devemos avisar ao servidor. Isso será feito disparando um evento, que chamarei de toggle_led.

Na linha 3, disparamos o evento toggle_led. Esse evento será “escutado” pelo servidor em tempo real, e terá como parâmetro a variável led_number, que possui o número do led cujo estado deve ser invertido. Por fim, precisamos atualizar o estado dos leds na tela do usuário quando o servidor acender ou apagar algum dos leds.

Nesse caso, o servidor disparará o evento changed, e enviará como parâmetro o estado atual dos dois leds. Assim, cada um dos leds recebe a classe HTML on ou off, dependendo de ele estar aceso ou apagado. Todos os usuários que estiverem utilizando a aplicação escutarão o evento changed quando o servidor modificar o estado de um dos leds. Assim, todos eles terão em sua tela o estado atualizado dos leds.

Servidor Node.js

Apesar de se uma aplicação simples, eu optei por utilizar o framework Express. Desse modo, se eu quiser fazer algo mais complexo futuramente, não haverá grandes dificuldades. Como eu já expliquei o básico sobre esse framework em outro artigo, vou explicar aqui apenas a parte referente à aplicação deste artigo.

Primeiramente, adicione os pacotes socket.iojohnny-five à sua aplicação. O pacote socket.io já foi explicado anteriormente, e o johnny-five é quem fará a comunicação com o Arduino. Abaixo, é feita a  inicialização dos leds e da comunicação com o Arduino .

Na linha 4, devemos informar a porta serial à qual o Arduino se encontra conectado. Na linha 7, o evento ready é disparado pela variável board após a comunicação ter sido estabelecida com a placa. Por fim, após a inicialização dos leds, a função ioChanged() avisará aos usuários da aplicação que o estado dos placa mudou, disparando o evento changed para a camada de interface do usuário. Essa função será apresentada a seguir.

Para permitir a comunicação em tempo real entre o servidor e a camada de interface, devemos inicializar o pacote socket.io, como a seguir.

Assim, quando um usuário se conectar ao servidor através da porta 5555, a função a seguir será executada.

Primeiramente, verificamos se a comunicação entre o servidor e o Arduino já foi estabelecida. Em caso afirmativo, o estado dos leds é enviado para o usuário que acabou de se conectar ao servidor através do evento changed. Na linha 5, sempre que esse usuário gerar o evento toggle_led para o servidor, o estado físico do led correspondente é alterado (linha 6), e, então, todos os usuários que estejam usando a aplicação no momento são avisados disso em tempo real (linha 7).

Por fim, segue a implementação da função ioChanged().

Camada de Hardware

Muito pouco precisa ser feito na camada de hardware para que a comunicação com o servidor seja feita. O pacote johnny-five, responsável por fazer essa comunicação, utiliza o protocolo Firmata. Sendo assim, precisamos gravar um programa no Arduino que seja implemente esse protocolo. Felizmente, a IDE do Arduino já vem com um exemplo que implementa o protocolo Firmata. Assim, só precisamos gravá-lo!

Para isso, vá em File -> Examples  -> Firmata  -> StardardFirmata, como mostra a Figura abaixo.

Feito isso, basta gravar o programa no Arduino, e a comunicação estará funcionando! Agora, basta conectar os leds aos pinos 2 e 13 do Arduino, para que a aplicação esteja finalizada.

 

 

Node.js: Criando um servidor REST com o Padrão MVC utilizando o Framework Express

Olá, já faz um bom tempo que não escrevo por aqui. Estou com pouco tempo livre devido a meu projeto de mestrado. Neste post falarei sobre parte de um projeto recente que venho desenvolvendo, durante o qual precisei criar um servidor REST com Node.js.

Sou um grande fã de CakePHP, pois foi o primeiro framework para web que tive contato, e com o qual aprendi bastante. Talvez por isso, sempre que aprendo uma nova linguagem, procuro encontrar analogias com alguma parte do CakePHP que eu já conheço. Sendo assim, procurei deixar a estrutura da aplicação o mais parecida possível com o que eu utilizava com CakePHP.

obs: se você não está familiarizado com o padrão MVC, leia este artigo.

Neste projeto, a maioria dos métodos dos models utilizam o pacote Bluebird para promessas. Além disso, o banco de dados que escolhi foi o MySQL. Algumas alterações na camada demodels podem ser necessárias se você quiser utilizar outro banco de dados.

O fonte completo da aplicação pode ser baixado aqui.

Estrutura básica da aplicação

Se você já estiver acostumado com o padrão MVC, não terá dificuldades para entender a função de cada diretório da aplicação. Há um diretório para os controllers e um para osmodels, mas nenhum para as views. Optei por retornar os dados do servidor apenas no formato JSON. Caso você deseje suporte para mais formatos, pode utilizar uma camada deviews separada da dos controllers para isso.

Antes de tudo, edite o arquivo config/config.js com as configurações de acesso ao banco de dados e a porta a ser utilizada pela aplicação. Você também pode especificar a porta através da variável de ambiente PORT.

Rotas

O Framework Express já possui um sistema de rotas bastante interessante, então pouco trabalho foi preciso aqui.

Cada controller possui uma função addRestRoutes que adiciona as rotas básicas do servidor automaticamente. Essas rotas mapeiam para ações presentes na classe Controller. Cadacontroller da sua aplicação deve herdar os métodos da classe Controller.

As rotas padrões são no formato a seguir:

  • GET /blog/1: mapeia para a ação findById
  • POST /blogs/searches: mapeia para a ação search
  • POST /blogs: mapeia para a ação create
  • PUT /blog/1: mapeia para a ação edit
  • DELETE /blog/1: mapeia para a ação delete

As ações search, create e edit requerem que alguns parâmetros sejam passados no corpo da requisição.

Para a ação de busca, os parâmetros devem ser passados seguindo o formato a seguir:

Para as ações create e put, devem ser passados os dados a serem salvos no banco de dados.

Se o controller possuir alguma rota que saia deste padrão, elas podem ser adicionadas pelo método addCustomRoutes como a seguir:

Controllers

A estrutura básica para um controller é a seguir.

O arquivo acima deve se chamar CarsController.js e estar na pasta controllers.

Models

Os models precisam de algumas configurações para o correto funcionamento dos métodos da classe Model. Um model básico é apresentado a seguir.

Os principais métodos herdados da classe Model são listados abaixo.

Model.find

Realiza uma consulta ao banco de dados.

Exemplo de Uso

Parâmetros

  • conditions : array de condições no formato do pacote squel
  • limit : máximo de registros para serem retornados
  • offset : números de registros para serem pulados
  • group : cláusula SQL group by
  • recursive : nível de recursividade para buscar por registros nos models com os quais este está associado

Model.findById

Busca por um registro com determinado id. Seu único parâmetro é o id do objeto a ser buscado. Este método retorna uma promessa rejeitada se não houver registro com o id especificado.

Model.save

Cria ou atualiza um registro já existente no banco de dados.

Exemplos de Uso

Model.delete

Remove um registro do banco e dados. Seu único parâmetro é o id do registro a ser removido.

Squel: Gerador de SQL para Node.js

Neste artigo falarei sobre o pacote squel, um gerador de SQL para Node.js. Utilizar um gerador é bastante produtivo, pois evita que tenhamos que escrever e debugar as queries diretamente. Abordarei apenas algumas consultas básicas, mas o pacote é bastante versátil.

Atenção: Embora o pacote também possa ser utilizado pelo browser, você não deve executar em seu servidor consultas geradas pelo cliente, uma vez que isso trás sérios problemas de segurança.

Instalação e Configuração

Para instalá-lo, e adicioná-lo automaticamente às dependências de seu package.json, digite

O pacote não precisa de nenhuma configuração para ser utilizado.

Utilização Básica

Retirei alguns exemplos da documentação oficial.

Insert

Select

Update

Delete

Utilizando Prepared Statements

Sempre que possivel, é recomendável a utilizaçao de prepared statements. Escrevi um artigo que mostra como utilizar prepared statements com o pacote node-mysql2, escrevendo as consultas SQL manualmente.

Para fazê-lo utilizando o pacote squel é bastante simples:

Ainda há muito mais. É possível utilizar subconsultas, condições bastante complexas e a geração de queries com comandos específicos para mysql e postgres. Vale a pena conferir a documentação completa!

Salvando suas views em Cache utilizando Redis e o Framework Express

Olá novamente. Nesse post, mostrarei como utilizar o pacote express-redis-cache para salvar suas views em cache, reduzindo, assim, o tempo de carregamento das páginas.

O pacote é bastante simples de ser utilizado, mas também é bastante completo. Utilizando-o no blog, não senti falta de nenhum recurso adicional. Seu desempenho também é bastante satisfatório, visto que os caches são armazenados num servidor Redis.

Instalação e Configuração

Para instalá-lo, adicione o pacote express-redis-cache às dependências de seu arquivopackage.json, ou digite

Neste tutorial assumirei que a versão do pacote express-redis-cache instalada é a mais recente até o momento (0.1.7).

Para utilizá-lo, devemos informar os parâmetros de conexão do servidor Redis.

O parâmetro prefix é utilizado para formar as string que identificarão cada uma das páginas armazenadas em cache.

Se você já tiver uma conexão Redis estabelecida, pode utilizar o parâmetro {client : redis_client} na inicialização, omitindo host, port e auth_pass. Se for necessário a utilização de senha para a conexão ser realizada, essa é, até o momento, a única forma de isso ser feito.

Utilização Básica

Para utilizar o pacote, devemos adicionar seu middleware a todas as rotas em que desejamos utilizá-lo.

Isso pedirá ao pacote para verificar se há alguma entrada de nome APP_NAME + '/' armazenada em cache. Em caso negativo, a função home será executada, e enviará a string ‘Welcome to my app’ como resposta à requisição.

Essa resposta será automaticamente salva em cache, com a entrada APP_NAME + '/'. Enquanto esse cache não expirar, a função home() não será mais executada.

Alterando o nome das Entradas

Você pode alterar o nome de uma entrada como a seguir.

ou fazendo

ou, ainda,

Decidindo Utilizar (ou não) Cache

Você pode escolher não utilizar a resposta armazenada em cache, mesmo se ela ainda não tiver expirado. Para isso, faça

Sobrescrevendo o parâmetro expire

Para alterar a vida útil padrão do cache, utilize

Excluindo entradas do cache

Você pode excluir entradas do cache, mesmo que elas ainda não tenham expirado.

Se você possui paginação em sua home, com cada página salva com as entradas home.page.0,home.page.1, e assim por diante, você pode excluir todas as entradas numa única chamada à função del().

Debugando

Várias mensagens de log são enviadas pelo pacote utilizado. Para escutá-las, faça

E é isso! Para aplicações de médio/grande porte, salvar as views em cache trará um ganho considerável de performance. Contudo, deve-se tomar cuidado para remover o cache sempre que o conteúdo do site for alterado. Afinal Você não quer uma página com um html antigo incluindo um javascript modificado, quer?

Gerando Sitemap para um Blog feito com o Framework Express para Node.js

Nesse artigo explicarei superficialmente o que são sitemaps, e mostrarei como gerá-los com um pacote já existente. Os exemplos práticos serão focados para a utilização em blogs, mas podem ser facilmente estendidos para qualquer tipo de página web. Os sitemaps gerados permanecerão em cache por 24 horas (tempo esse que pode ser modificado livremente, dependendo do volume de atualização de seu blog).

Optei por utilizar o pacote sitemap, que não é específico para Express, mas que é bastante simples de utilizar e que possui um sistema de caches interessante. Há o pacote express-sitemap, para Express, mas que funciona melhor para sites compostos por páginas estáticas. Para um blog, não encontrei muitas vantagens em utilizá-lo no lugar do pacote sitemap.

Se você já sabe o básico sobre sitemaps, a primeira seção do artigo pode ser ignorada.

Introdução aos sitemaps

Sitemap é um protocolo feito para facilitar a indexação das páginas de um site pelos mecanismos de pesquisa. Ele pode consistir de apenas um arquivo de texto, em que cada linha corresponde à URL de uma página do site que você deseje indexar.

Naturalmente, o fato de uma URL não estar no sitemap não quer dizer que ela não será exibida nas páginas de busca (se é isso o que você deseja, leia sobre robots.txt), e uma URL estar em seu sitemap não quer dizer que ela aparecerá na primeira página de nenhum mecanismo de busca.

Os sitemaps servem apenas como facilitadores, assegurando que nenhuma página de seu site deixe de ser analisada pelos mecanismos de pesquisa, e permitindo que você diga, por exemplo, quais páginas considera mais importantes em seu site.

A forma mais comum de se utilizar sitemaps é através de um arquivo XML, que contém, entre outras informações, a última vez em que cada página foi atualizada e, em média, quão frequentes são essas atualizações.

Acima, a página http://www.example.com/ foi modificada pela última vez em 01/01/2015, espera-se que seja modificada mensalmente, e possui prioridade 0.8 (numa escala de 0 a 1). Uma prioridade maior não garante que sua página aparecerá mais bem posicionada nas buscas, mas diz quais páginas, dentro de seu site, você considera mais importantes.

Instalação e Configuração do Pacote Sitemap

Para instalar o pacote, adicione sitemap às dependências de seu arquivo package.json, ou execute o comando

A seguir, crie o arquivo routessitemap.js, e adicione-o a seu objeto app.

Você pode, então, criar seu objeto sitemap como a seguir.

Acesse seusite/sitemap.xml, e você verá o XML do sitemap, ainda sem a URL de nenhuma página.

Adicionando seus Posts ao Sitemap

Agora, você deve obter as URLs de seu blog, para adicioná-las ao objeto sm. Nem todas as URLs precisam ser adicionadas, mas apenas aquelas que possuam conteúdo relevante. Por exemplo, URLs de paginação ou de filtros, em geral, não possuem conteúdo novo: são apenas formas de facilitar a navegação dentro do site, para que o usuário encontre o que deseja.

Sendo assim, optei por adicionar ao sitemap apenas as URLs referentes aos posts do blog.

O método sm.toXML() verifica há quanto tempo o último XML foi gerado, para determinar se é preciso renovar o XML ou se o último gerado ainda é válido. Isso trás um ganho considerável no tempo de geração do mesmo, se seu sitemap possuir muitas páginas.

Caso você prefira utilizar o pacote express-sitemap, poucas alterações teriam de ser efetuadas. A principal é referente ao cache, que não é gerenciado pelo pacote. Assim, você poderia, por exemplo, utilizar cron jobs para gerar o XML, e salvar em public/sitemap.xml a intervalos regulares, ou salvar numa variável o timestamp da última vez que o sitemap foi gerado.

Utilizando Node.js com banco de dados MySQL

Olá! Neste post, falaremos sobre a utilização de bancos de dados MySQL com Node.js! Utilizarei o driver node-mysql2.

Instalação

Para instalá-lo, execute o comando

A instalação também pode ser feita adicionando o pacote mysql2 à lista de dependências de seu arquivo package.json. Para maiores detalhes consulte package.json.

Configuração

Crie o arquivo `config/database.js’ em seu projeto, e adicione as linhas a seguir, fazendo as alterações necessárias nos parâmetros de configuração.

Veja a lista completa das possíveis configurações aqui.

Utilização Básica

Para estabelecer uma conexão com o banco de dados, adicione as linhas a seguir.

Para realizar operações de banco de dados, é bastante simples:

O método end() fecha a conexão com o banco de dados, aguardando que todas as consultas pendentes sejam realizadas antes disso.

Prepared Statements

Para proteger-se contra SQL Injection, recomenda-se a utilização de prepared_statementssempre que uma consulta utilizar dados vindos do usuário. Além disso, quando várias consultas similares forem utilizadas, as consultas são executadas de maneira muito mais eficiente.

Se preferir, você pode preparar o statement manualmente.

Utilizando Pool de Conexões

Você pode, também, utilizar um pool de conexões. Para tanto, adicione ao arquivoconfig/database.js a seguinte linha:

Esse parâmetro diz o número máximo de conexões que podem ser realizadas em simultâneo com o banco de dados.

A seguir, podemos obter conexões do pool.

Transações

Utilizar transações é bastante simples.

O tratamento de erros foi simplificado por questões de legibilidade.

As funções beginTransaction, commite rollback são apenas formas simplificadas de se executar os comandos START_TRANSACTION, COMMIT e ROLLBACK no banco de dados. Contudo, alguns comandos podem gerar commits implícitos.

Utilizando Promessas

Infelizmente este pacote não suporta, nativamente, a utilização de promessas. Contudo, você pode utilizar as funções promisify() e promisifyAll() do pacote bluebird.

Jade: Criando Blocos Reutilizáveis com Mixins

Os benefícios da modularização já foram amplamente estudados na Engenharia de Software, e não são o foco deste artigo. Nele explicarei apenas o que for relevante do ponto de vista da implementação. Caso esteja interessado, consulte também a documentação oficial (em inglês) sobre como implementar herança de views.

Todos os exemplos utilizados neste artigo foram retirados da documentação oficial (em inglês).

Mixins

Mixins são blocos reutilizáveis de código, permitindo uma melhor organização de nossas views.

Primeiramente, vejamos um exemplo simples, que ilustra a declaração e o uso de mixins.

O código Jade abaixo

gera o HTML

Simples, não? O mixin list pode ser utilizado em qualquer arquivo .jade, desde que o arquivo de sua declaração seja devidamente incluído.

Passagem de parâmetros

Vejamos, agora, um exemplo um pouco mais útil, em que o mixin recebe parâmetros para gerar saídas customizadas.

gera o HTML

Blocos

Além disso, mixins podem receber blocos como parâmetro, para produzirem parte da (ou toda a) saída.

gera o HTML

Atributos Nomeados

Também é possível utilizar atributos nomeados, como mostra o exemplo abaixo.

produzindo o HTML

Por padrão, os atributos são escapados durante a chamada da função. Assim, eles devem ser utilizados no mixin em conjunto com o operador !, para evitar que sejam escapados duas vezes.

Número Deconhecido de Parâmetros

Por fim, ainda é possível utilizar mixins que recebam um número desconhecido de parâmetros.

O código Jade abaixo

produz o HTML

Introdução ao Framework Express

Express é um framework para node.js para a criação de aplicações web. Seu foco está, principalmente, na utilização de rotas para redirecionar cada requisição feita às funções corretas.

Uma mesma requisição pode ser atendida por várias funções, denominadas middlewares, que podem, por exemplo, manipular os dados recebidos via post para que sejam apresentados de maneira mais tratável aos demais middlewares.

Neste post explicarei como instalar o framework, e darei mais detalhes sobre o que são middlewares e como eles funcionam. Por fim, listarei alguns middlewares que considero bastante úteis.

Instalação

Inicialmente, execute o comando

Isso instalará um gerador de projetos próprio do express. A seguir, digite

Isso criará um diretório chamado myapp, com um aplicativo já pré-configurado para utilizar as funcionalidades básicas do express. Além disso, toda a estrutura de diretórios também será criada, incluindo uma pasta pública para seus assets.

Para iniciar seu servidor, digite

Veja que o código básico da sua aplicação fica no arquivo app.js.

Middlewares

Toda conexão feita ao servidor deve ser tratada por um ou mais middlewares, desde uma requisição para obtenção de algum recurso num servidor REST até uma simples requisição para baixar o favicon do site.

Cada middleware deve registrar-se no objeto do tipo express, normalmente denominadoapp, informando quais tipos de requisição deseja tratar. Opcionalmente, o middleware pode escolher receber todas as requisições feitas. Isso é feito através do método app.use (veja a documentação aqui).

A forma mais simples de se utilizar o método use é

Esse trecho de código diz ao objeto app que toda requisição feita a path deve ser tratada pela função middleware. O parâmetro path é opcional, e, se omitido, é assumido como sendo ‘/’, o que fará com que a função middleware seja chamada para atender todas as requisições feitas ao servidor.

Os parâmetros req e res possuem, respectivamente, os dados da requisição feita ao servidor e da resposta que será enviada. next é uma função que diz ao objeto app que outrosmiddlewares devem ser executados para terminar o processamento da requisição.

Vejamos alguns exemplos:

O código acima busca por usuários com id req.params.id, e retorna seus dados no formato JSON. Podemos melhorá-lo para aceitar apenas ids numéricos fazendoapp.use('/users/:id([0-9]{1,})').

No blog, utilizei o código abaixo para liberar acesso á área interna.

app.js

routes/admin.js

O exemplo acima ilustra como podemos dividir as rotas em arquivos diferentes, para melhorar a organização do código. A função router.all diz que todos os tipos de requisição devem ser tratados pelo middleware isLogged.

Se o usuário que estiver tentando acessar o admin estiver logado, a função next é executada, e os demais middlewares podem prover o recurso solicitado. Caso contrário, o usuário é redirecionado para a tela de login.

Os principais middlewares que utilizei no blog foram

  1. body-parser – parser para os dados enviados no corpo da requisição. utilizo este middleware para facilitar o acesso aos dados enviados via POST ou PUT;
  2. less-middleware – Compilador para LESS, esse middleware intercepta todas as requisições feitas a arquivos .css, procura pelos arquivos .less correspondentes e os compila, caso tenham sido alterados desde a última compilação;
  3. express-morgan – gera logs de acessos de todas as requisições http feitas. esses logs podem ser enviados para o console ou para um arquivo de texto qualquer.;
  4. express-session como o nome diz, esse middleware é responsável por tratar as sessões dos usuários. Ele não armazena as sessões por si próprio, mas necessita receber como parâmetro algum objeto capaz de fazer esse armazenamento. Cada middlewareexecutado depois dele possuirá acesso direto à sessão do usuário através do objetoreq.session.

Num post futuro espero explicar com mais detalhes cada um desses middlewares. Até a próxima ;)

Autenticação com Node.js e Express

A autenticação é uma parte muito importante de praticamente qualquer aplicação. Esse post explica como autenticar usuários num servidor Node.js, utilizando o framework Express, e armazenando as sessões com Redis.

Configurando a Sessão

Para autenticar usuários, devemos, antes, configurar corretamente a sessão do Express. Para isso, primeiro, instale o pacote express_session através do comando

A seguir, você deve configurar o pacote instalado, como abaixo.

Dessa forma, quando uma requisição estiver sendo atendida, as informações da sessão pode ser acessadas (ou alteradas) por meio do objeto req.session.

Tentativa de Login

Assim, a rotina de login do blog ficou como abaixo.

 

Para os dados enviados via POST possam ser acessados da forma acima, devemos utilizar o pacote body-parser, adicionando as linhas

 

à rotina de inicialização do Express.

Protegendo a senha do Usuário

Muito já foi discutido sobre o porquê de criptografar todas as senhas salvas no banco de dados. Em resumo, se alguém mal intencionado tiver acesso ao banco de dados, ele, no mínimo, terá muito trabalho para descobrir as senhas cadastradas se elas estiverem criptografadas. Como muitas pessoas utilizam as mesmas senhas em vários serviços, isso é muito importante.

Para a criptografia, utilizei o pacote bcrypt. É uma boa prática utilizar uma string de salt para cada usuário. Isso se deve ao fato de que muitos usuários utilizam senhas iguais, como12345678 ou password. Assim, se todos eles utilizarem a mesma string de salt, um usuário com acesso ao banco de dados poderia procurar por senhas repetidas e fazer algumas tentativas com senhas comuns para recuperar as senhas originais.

Para utilizar o bcrypt no windows, precisei instalar o Visual Studio. Uma versão gratuita pode ser baixada aqui.

Assim, minha função de login consiste dos seguintes passos:

  1. Verifica se há algum usuário com o e-mail informado pelo usuário;
  2. Obtém a string de salt desse usuário;
  3. Criptografa a senha informada pelo usuário com o salt obtido;
  4. Verifica se essa senha pertence à conta correspondente ao e-mail informado.

A implementação da rotina segue abaixo.

 

Introdução ao Node.js

Node.js possui algumas características que o tornam bastante peculiar, mas uma das mais importantes é o fato de que todas as conexões feitas ao servidor compartilham a mesma thread.

Isso significa que, se o servidor estiver lidando com mil conexões simultaneamente, uma única thread é responsável por gerir todas as mil conexões.

Desse modo, o servidor pode lidar com várias conexões simultaneamente, utilizando uma quantidade de memória RAM não muito maior do que utilizaria com apenas uma conexão, diferente do que acontece com PHP, por exemplo.

Alguém com um conhecimento básico em threads pode ter percebido que isso também trás algumas limitações.

Como o servidor só pode suprir uma conexão por vez, se uma conexão precisar fazer operações lentas, como cálculos matemáticos pesados ou o redimensionamento de imagens grandes, deixando o servidor ocupado, nenhuma outra conexão conseguirá ser atendida. Por esse motivo, as requisições feitas devem ser atendidas processadas rapidamente!

Operações de I/O, como acesso a banco de dados ou a servidores externos, são realizadas de maneira assíncrona, como requisições Ajax convencionais. Essas operações são coordenadas por threads separadas, mas uma vez que todos os dados foram obtidos, eles são passados para a thread principal através de uma função de callback. Desse modo, enquanto uma thread busca os dados de um post do blog no banco de dados, um trecho de outra conexão pode ser processado.

Além disso, Node.js é ideal para o desenvolvimento de aplicações que respondam a eventos em tempo real, como um chat. Quando um usuário envia uma mensagem em uma sala de bate-papo, é razoável esperar que todos os membros da sala recebam a mensagem no mesmo instante.

Um programador pouco experiente poderia pensar em implementar isso fazendo requisições ajax para o servidor constantemente, verificando a existência de novas mensagens (já aconteceu comigo!). O problema é que isso provocaria uma carga enorme no servidor. Na verdade, com um número não muito grande de usuários, o efeito seria bem parecido com o de um ataque DDOS.

Para resolver esse problema, ao invés de se criar constantemente novas conexões entre cada cliente e o servidor, cria-se apenas uma conexão (por cliente), que permanece aberta o tempo todo. Através dessa conexão, cliente e servidor podem trocar mensagens de maneira extremamente rápida.

Da maneira tradicional, para transmissão de informações pequenas, perde-se muito mais tempo para o estabelecimento de novas conexões do que transmitindo a mensagem. Se sentir necessidade, o leitor pode se informar mais sobre HTTP e TCP.

Já com conexões persistentes, a conexão é estabelecida apenas uma vez, e sempre que preciso, as mensagens podem ser enviadas através dela.

Não acrescentarei nada de programação neste post, pois ele já está demasiadamente grande, mas espero em breve postar algumas linhas de código :)