33
4.4
Gerando scaffold do projeto . . . . . . . . . . . . . . . . . . . . . . . .
35
4.5
Organizando os diretórios do projeto . . . . . . . . . . . . . . . . . . .
38
5
Dominando o Express
43
5.1
Estruturando views . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
5.2
Controlando as sessões de usuários . . . . . . . . . . . . . . . . . . . . 44
5.3
Criando rotas no padrão REST
. . . . . . . . . . . . . . . . . . . . . . 49
5.4
Aplicando filtros antes de acessar as rotas . . . . . . . . . . . . . . . .
54
5.5
Indo além: criando páginas de erros amigáveis . . . . . . . . . . . . .
56
6
Programando sistemas real-time
61
6.1
Como funciona uma conexão bidirecional? . . . . . . . . . . . . . . .
61
6.2
Conhecendo o framework Socket.IO . . . . . . . . . . . . . . . . . . . 62
6.3
Implementando um chat real-time . . . . . . . . . . . . . . . . . . . .
63
6.4
Organizando o carregamento de Sockets . . . . . . . . . . . . . . . . . 69
6.5
Socket.IO e Express em uma mesma sessão . . . . . . . . . . . . . . . 70
6.6
Gerenciando salas do chat . . . . . . . . . . . . . . . . . . . . . . . . .
73
6.7
Notificadores na agenda de contatos . . . . . . . . . . . . . . . . . . .
77
6.8
Principais eventos do Socket.IO . . . . . . . . . . . . . . . . . . . . . . 80
7
Integração com banco de dados
83
7.1
Bancos de dados mais adaptados para Node.js . . . . . . . . . . . . . .
83
7.2
MongoDB no Node.js utilizando Mongoose . . . . . . . . . . . . . . .
85
7.3
Modelando com Mongoose . . . . . . . . . . . . . . . . . . . . . . . . . 86
7.4
Implementando um CRUD na agenda de contatos . . . . . . . . . . .
87
7.5
Persistindo estruturas de dados com NoSQL Redis . . . . . . . . . . .
91
7.6
Mantendo um histórico de conversas do chat . . . . . . . . . . . . . . 92
x
Casa do Código
Sumário
8
Preparando um ambiente de testes
97
8.1
Mocha, o framework de testes para Node.js . . . . . . . . . . . . . . .
97
8.2
Criando um Environment para testes . . . . . . . . . . . . . . . . . . . 98
8.3
Instalando e configurando o Mocha . . . . . . . . . . . . . . . . . . . . 100
8.4
Rodando o Mocha no ambiente de testes . . . . . . . . . . . . . . . . . 101
8.5
Testando as rotas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
8.6
Deixando seus testes mais limpos . . . . . . . . . . . . . . . . . . . . . 109
9
Aplicação Node em produção
111
9.1
O que vamos fazer? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
9.2
Configurando Clusters . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
9.3
Redis controlando as sessões da aplicação . . . . . . . . . . . . . . . . 114
9.4
Monitorando aplicação através de logs . . . . . . . . . . . . . . . . . . 116
9.5
Otimizações no Express . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
9.6
Otimizando requisições do Socket.IO . . . . . . . . . . . . . . . . . . . 119
9.7
Aplicando Singleton nas conexões do Mongoose . . . . . . . . . . . . 122
9.8
Mantendo o sistema no ar com Forever . . . . . . . . . . . . . . . . . . 122
9.9
Integrando Nginx no Node.js
. . . . . . . . . . . . . . . . . . . . . . . 124
10 Continuando os estudos
129
Índice Remissivo
131
xi
Capítulo 1
Bem-vindo ao mundo Node.js
1.1
O problema das arquiteturas bloqueantes
Os sistemas para web desenvolvidos sobre plataforma .NET, Java, PHP, Ruby ou
Python possuem uma característica em comum: eles paralisam um processamento
enquanto utilizam um I/O no servidor. Essa paralisação é conhecida como modelo
bloqueante (Blocking-Thread). Em um servidor web podemos visualizá-lo de forma
ampla e funcional. Vamos considerar que cada processo é requisição feita pelo usuá-
rio. Com o decorrer da aplicação, novos usuários vão acessando-a, gerando uma
requisição no servidor. Um sistema bloqueante enfileira cada requisição e depois as
processa, uma a uma, não permitindo múltiplos processamentos delas. Enquanto
uma requisição é processada as demais ficam em espera, mantendo por um período
de tempo uma fila de requisições ociosas.
Esta é uma arquitetura clássica, existente em diversos sistemas pelo qual possui
um design ineficiente. É gasto grande parte do tempo mantendo uma fila ociosa
enquanto é executado um I/O. Tarefas como enviar e-mail, consultar o banco de
dados, leitura em disco, são exemplos de tarefas que gastam uma grande fatia desse
1.2. E assim nasceu o Node.js
Casa do Código
tempo, bloqueando o sistema inteiro enquanto não são finalizadas. Com o aumento
de acessos no sistema, a frequência de gargalos serão mais frequentes, aumentando
a necessidade de fazer um upgrade nos hardwares dos servidores. Mas upgrade das
máquinas é algo muito custoso, o ideal seria buscar novas tecnologias que façam bom
uso do hardware existente, que utilizem ao máximo o poder do processador atual,
não o mantendo ocioso quando o mesmo realizar tarefas do tipo bloqueante.
1.2
E assim nasceu o Node.js
Figura 1.1: Logotipo do Node.js.
Foi baseado neste problema que, no final de 2009, Ryan Dahl com a ajuda inicial de