Artigo original: https://www.freecodecamp.org/news/simple-chat-application-in-node-js-using-express-mongoose-and-socket-io-ee62d94f5804/
Escrito por: Arun Mathew Kurian
Neste tutorial, usaremos a plataforma do Node.js para criar uma aplicação de bate-papo em tempo real que envia e exibe mensagens a um destinatário instantaneamente, sem precisar atualizar a página. Usaremos o framework Express.js do JavaScript e as bibliotecas Mongoose e Socket.io para conseguir isso.
Antes de começarmos, vamos dar uma rápida olhada no básico a respeito do Node.js
Node.js
O Node.js é um ambiente de tempo de execução do JavaScript, de código aberto e multiplataforma, que executa código em JavaScript fora do navegador. A vantagem mais importante de usar o Node é podermos usar o JavaScript tanto como linguagem de front-end quanto de back-end.
Como já sabermos, o JavaScript foi usado primordialmente como linguagem de scripts do lado do client, onde os scripts eram integrados no HTML de uma página da web e executados por um mecanismo de JavaScript no navegador da web do usuário.
O Node.js permite que os desenvolvedores usem o JavaScript para escrever ferramentas de linha de comando e scripts para o lado do servidor — executando os scripts do lado do servidor de modo a produzir conteúdo dinâmico para a página da web antes mesmo de a página ser enviada ao navegador da web do usuário.
Para instalar o node, acesse:
https://nodejs.org/en/download/
Embora o Node seja de thread única, ele ainda é mais rápido para o uso de funções assíncronas. O Node pode processar outras coisas enquanto um arquivo estiver sendo lido no disco ou enquanto aguarda que uma solicitação de HTTP seja concluída. O comportamento assíncrono pode ser implementado usando funções de callback. Além disso, o JavaScript funciona bem com o JSON e com bancos de dados No-SQL.
Módulos do NPM
O Node.js permite que os módulos de bibliotecas sejam incluídos na aplicação. Esses módulos podem ser definidos pelo usuário ou de terceiros.
Os módulos de terceiros podem ser instalados usando o seguinte comando:
npm install nome_do_módulo
e os módulos instalados podem ser usados por meio da função require():
var module = require('nome_do_módulo')
Nas aplicações do Node, usaremos um arquivo package.json para manter as versões dos módulos. Esse arquivo pode ser criado através deste comando:
npm init
Os pacotes, por sua vez, podem ser instalados assim:
npm install -s nome_do_módulo
Existem muitos frameworks que podem ser adicionados como módulos em nossa aplicação do Node. Eles serão explicados mais adiante, conforme for necessário.
Aplicação de bate-papo simples
A aplicação deve permitir que diversos usuários possam bater papo juntos. As mensagens devem ser atualizadas sem que seja preciso atualizar a página. Para fins de simplicidade, desconsideraremos a parte da autenticação.
Podemos começar criando um diretório para o projeto e navegando para ele. Em seguida, podemos iniciar nosso projeto usando o seguinte comando:
npm init
Isso nos levará a inserir detalhes sobre o projeto.
Depois disso, será criado um arquivo package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Nosso diretório da aplicação agora está pronto.
A primeira coisa que precisamos criar é um servidor. Para criá-lo, faremos uso de um framework chamado Express.
Express.js
O Express.js, ou, simplesmente, Express, é um framework para aplicações da web para o Node.js. O Express fornece um conjunto bastante abrangente de recursos para aplicações para a web e dispositivos móveis (em inglês). O Express fornece uma camada fina de recursos de aplicações para a web fundamentais, sem obscurecer os recursos do próprio Node.js.
Instalaremos o Express.js usando o seguinte comando:
npm install -s express
Dentro do arquivo package.json, será adicionada uma linha nova:
"dependencies": {
"express": "4.16.3"
}
Em seguida, criaremos um arquivo server.js.
Nesse arquivo, precisaremos solicitar o Express e criar uma referência a uma variável de instância do Express. O conteúdo estático, como o HTML, o CSS ou o JavaScript pode ser servido usando o express.js:
var express = require('express');
var app = express();
Também podemos começar a "escutar" em uma porta usando o código abaixo:
var server = app.listen(3000, () => {
console.log('server is running on port', server.address().port);
});
Agora, precisamos criar um arquivo HTML chamado index.html, que exibe nossa interface de usuário (UI). Adicionei aqui o CDN para o Bootstrap e para o JQuery .
//index.html
<!DOCTYPE html>
<html>
<head>
<! — incluir os CDNs do Bootstrap e do JQuery →
</head>
<body>
<div class="container">
<br>
<div class="jumbotron">
<h1 class="display-4">Send Message</h1>
<br>
<input id = "name" class="form-control" placeholder="Name">
<br>
<textarea id = "message" class="form-control" placeholder="Your Message Here">
</textarea>
<br>
<button id="send" class="btn btn-success">Send</button>
</div>
<div id="messages">
</div>
</div>
<script>
</script>
</body>
</html>
Observe que a tag <script> </script>
vazia será o local onde escreveremos o código em JavaScript do lado do client.
Para informar ao Express que usaremos um arquivo estático, adicionaremos uma nova linha em server.js:
app.use(express.static(__dirname));
Podemos executar server.js usando o comando
node ./server.js
ou um pacote chamado nodemon, de modo que as alterações feitas no código sejam detectadas automaticamente. Faremos o download do nodemon usando o comando
npm install -g nodemon
A flag -g significa 'global', e serve para que o nodemon esteja acessível em todos os projetos.
Executaremos o código usando o comando
nodemon ./server.js
Se você for para localhost:3000 no navegador, verá o arquivo index.html sendo exibido:

Agora que nosso servidor está em execução, precisamos criar nosso banco de dados. Para esta aplicação, usaremos um banco de dados No-SQL e usaremos o Mongodb. Estou configurando meu mongodb em MongoDB Atlas. O banco de dados terá uma única coleção, chamada messages, com os campos name e message.
Para conectarmos esse banco de dados à aplicação, usaremos outro pacote, chamado Mongoose.
Mongoose
O Mongoose é uma ferramenta de modelagem de objetos do MongoDB projetada para funcionar em um ambiente assíncrono. O Mongoose pode ser instalado usando o comando
npm install -s mongoose
Dentro de server.js, precisamos solicitar o mongoose:
var mongoose = require('mongoose');
Então, atribuiremos a uma variável o URL de nosso banco de dados:
var dbUrl = 'mongodb+srv://username:password@ds257981.mongodb.net:57981/simple-chat'
O Mongoose se conectará com o bando de dados por meio do método connect:
mongoose.connect(dbUrl , (err) => {
console.log('mongodb connected',err);
})
E definiremos nosso modelo de mensagem assim:
var Message = mongoose.model('Message',{ name : String, message : String})
Podemos implementar a lógica de bate-papo agora. Antes disso, no entanto, precisamos fazer alguns ajustes ao arquivo server.js.
Logo abaixo de var app = express();
, adicione o código a seguir ao arquivo:
app.use(express.json());
app.use(express.urlencoded({extended: false}))
Roteamento
O roteamento se refere a como os endpoints de uma aplicação (URIs) respondem às solicitações do client. Você define o roteamento usando métodos do objeto da aplicação do Express que correspondem a métodos HTTP: app.get() para lidar com as solicitações GET e app.post() para lidar com as solicitações POST.
Esses métodos de roteamento especificam uma função de callback (texto em inglês), a qual às vezes também recebe o nome de "função de tratamento", chamada quando a aplicação recebe uma solicitação para a rota (endpoint) especificada e o método HTTP. Em outras palavras, a aplicação "escuta" as solicitações que correspondem às rotas e aos métodos especificados. Quando uma correspondência é detectada, ela chama a função de callback especificada.
Agora, precisamos criar duas rotas para as mensagens para que nosso bate-papo funcione.
No server.js:
get: receberá todas as mensagens do banco de dados
app.get('/messages', (req, res) => {
Message.find({},(err, messages)=> {
res.send(messages);
})
})
post: publicará novas mensagens criadas pelo usuário no banco de dados
app.post('/messages', (req, res) => {
var message = new Message(req.body);
message.save((err) =>{
if(err)
sendStatus(500);
res.sendStatus(200);
})
})
Para se conectar com essas rotas ao front-end, precisamos adicionar o código abaixo na tag script do lado do client no index.html:
$(() => {
$("#send").click(()=>{
sendMessage({
name: $("#name").val(),
message:$("#message").val()});
})
getMessages()
})
function addMessages(message){
$("#messages").append(`
<h4> ${message.name} </h4>
<p> ${message.message} </p>`)
}
function getMessages(){
$.get('http://localhost:3000/messages', (data) => {
data.forEach(addMessages);
})
}
function sendMessage(message){
$.post('http://localhost:3000/messages', message)
}
Aqui, sendMessage é usada para invocar a rota de post das mensagens e salvar uma mensagem enviada pelo usuário. A mensagem é criada quando o usuário clica no botão Send.
Da mesma forma, getMessage é usada para invocar a rota de get das mensagens. Ela obterá todas as mensagens salvas no banco de dados e será incluída na div de mensagens.

A única questão agora é que não há como o client saber se o servidor foi atualizado. Assim, a cada vez que publicarmos uma mensagem, precisaremos atualizar a página para ver as novas mensagens.
Para resolver isso, podemos adicionar uma sistema de notificações push que enviará mensagens do servidor para o client. No Node.js, usamos o socket.io.
Socket.io
O Socket.IO é uma biblioteca do JavaScript para aplicações da web em tempo real. Essa biblioteca permite a comunicação em tempo real e bidirecional entre clients da web e um servidor (texto em inglês). Ela tem duas partes: uma biblioteca para o client, executada no navegador, e uma biblioteca para o servidor, para o Node.js. O Socket.io permite a comunicação bidirecional baseada em eventos e em tempo real.
Para instalar o socket.io:
npm install -s socket.io
também precisamos do pacote HTTP para que o Socket.io funcione:
npm install -s http
Adicione o código a seguir ao arquivo server.js:
var http = require(‘http’).Server(app);
var io = require(‘socket.io’)(http);
Logo, criamos uma conexão:
io.on('connection', () =>{
console.log('a user is connected')
})
No index.html, adicione a tag abaixo:
<script src="/socket.io/socket.io.js"></script>
Agora, precisamos criar uma ação de emissão no server.js para quando uma mensagem é criada. A rota de post, portanto, fica assim:
app.post('/messages', (req, res) => {
var message = new Message(req.body);
message.save((err) =>{
if(err)
sendStatus(500);
io.emit('message', req.body);
res.sendStatus(200);
})
})
Para a tag de script do lado do client, por sua vez, adicione o seguinte código ao arquivo index.html:
var socket = io();
socket.on('message', addMessages)
Desse modo, cada vez que uma mensagem for publicada, o servidor atualizará as mensagens na div de mensagens.

Pronto!
Essa é uma aplicação bastante básica que podemos criar no Node.js. Há lugar para fazermos muitas melhorias. O código final pode ser encontrado em https://github.com/amkurian/simple-chat
server.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');
app.use(express.static(__dirname));
app.use(express.json());
app.use(express.urlencoded({extended: false}))
var Message = mongoose.model('Message',{
name : String,
message : String
})
var dbUrl = 'mongodb+srv://username:password@ds257981.mongodb.net:57981/simple-chat'
app.get('/messages', (req, res) => {
Message.find({},(err, messages)=> {
res.send(messages);
})
})
app.get('/messages', (req, res) => {
Message.find({},(err, messages)=> {
res.send(messages);
})
})
app.post('/messages', (req, res) => {
var message = new Message(req.body);
message.save((err) =>{
if(err)
sendStatus(500);
io.emit('message', req.body);
res.sendStatus(200);
})
})
io.on('connection', () =>{
console.log('a user is connected')
})
mongoose.connect(dbUrl ,{useMongoClient : true} ,(err) => {
console.log('mongodb connected',err);
})
var server = http.listen(3001, () => {
console.log('server is running on port', server.address().port);
});
Espero que este artigo tenha sido útil no entendimento de alguns conceitos básicos.
Alguns links úteis (em inglês):