Alura > Cursos de Programação > Cursos de Node.JS > Conteúdos de Node.JS > Primeiras aulas do curso WebSockets: implemente comunicações em tempo real com Socket.IO e MongoDB

WebSockets: implemente comunicações em tempo real com Socket.IO e MongoDB

Criando o Alura Docs - Apresentação

Boas-vindas a esse curso de WebSockets! Meu nome é Antônio Evaldo e sou instrutor aqui na Alura.

Antônio Evaldo é uma pessoa de pele clara, olhos escuros e cabelos escuros encaracolados. Usa bigode e cavanhaque e está com os cabelos amarrados atrás da cabeça. Veste uma camiseta azul-escura. Ao fundo, há uma parede azul e um quadro de uma guitarra vermelha.

Esse curso é para você, que já conhece o protocolo HTTP e quer conhecer uma nova forma de desenvolver uma aplicação web usando o protocolo WebSockets.

Protocolo WebSockets

Basicamente, esse protocolo permite o desenvolvimento de aplicações que possuem comunicação em tempo real entre cliente e servidor. Por exemplo, em aplicações onde há um bate-papo em tempo real ou mesmo em jogos online.

Neste curso o nosso projeto será o AluraDocs. Na tela do AluraDocs temos uma lista centralizada, com três links, o primeiro para um documento de JavaScript, o segundo para um documento de Node e o terceiro para um documento de Socket.IO. Abaixo temos um campo para adicionar um novo documento e ao lado direito desse campo um botão "Adicionar documento".

Esse é um projeto feito a pedido de duas amigas fictícias que usaremos para exemplificar: a Eduarda e a Juliana. Elas são duas amigas que gostam muito de programação e de compartilhar conhecimento entre elas.

Neste projeto, se uma delas clicar em "JavaScript" por exemplo, vai para uma nova página que tem um grande campo de texto e abaixo dele, do lado esquerdo, o botão "Voltar" e, do lado direito, o botão "Excluir".

Neste campo de texto elas podem escrever qualquer coisa sobre o que aprenderam sobre JavaScript.

Mas, vejamos o que acontece se duas pessoas estiverem nesta página ao mesmo tempo. Para simular essa situação, vou duplicar esta aba do navegador e colocar as duas abas lado a lado.

Note que, ao escrever um texto na aba do lado direito, esse texto aparece sendo escrito na aba do lado esquerdo ao mesmo tempo que estou escrevendo.

É exatamente essa interação em tempo real que o protocolo WebSockets permite. E aprenderemos a fazer isso ao longo do curso.

Além disso, aprenderemos como excluir o documento utilizando o banco de dados ou adicionar um novo documento.

E todas essas interações estão totalmente funcionais. Há várias interações em tempo real e vamos implementar todas elas.

Você vai:

Pré-requisito:

Antes de fazer este curso é importante que você tenha completado pelo menos a formação JavaScript para back-end.

E é desejável que você tenha feito o curso Node.js: API Rest com Express e MongoDB. Se você fizer esse curso terá familiaridade com o Express e MongoDB, que vamos utilizar neste curso e poderá focar seu aprendizado no WebSockets e Socket.IO.

Vamos lá? Estou ansioso para te mostrar esses conhecimentos. Te espero no curso!

Criando o Alura Docs - WebSockets e HTTP

No exemplo que usaremos neste curso, Eduarda e Juliana são duas amigas que gostam de programação e de compartilhar os conhecimentos delas entre si. Por isso, pediram para nós desenvolvermos uma aplicação web onde elas poderiam trocar esses conhecimentos. Esta aplicação é a AluraDocs.

Eu me antecipei e já fiz a interface dessa parte inicial. Na tela inicial temos acesso a três documentos que elas estudam:

Abaixo desses links temos um campo para adicionar um novo documento e um botão "Adicionar documento". Esse botão ainda não funciona, vamos implementar as funcionalidades aos poucos.

Quero te mostrar o seguinte: digamos que a Eduarda entre no documento de Node, por exemplo, e escreva: "Olha que bacana o que eu aprendi sobre Node".

Como faríamos, com o protocolo HTTP, para salvar o que ela escreveu num banco de dados, por exemplo?

Em algum local da tela teríamos um botão chamado "Salvar". E, após escrever o texto, ela clicaria nesse botão para salvar o texto no banco de dados. Mas se, segundos depois, a Juliana também escrever algo e salvar o texto, a alteração da Juliana vai sobrescrever o que a Eduarda salvou primeiro.

Aconteceria um problema de comunicação e de sincronização de informações, que é justamente um problema do protocolo HTTP, onde sempre teremos uma requisição feita pelo cliente e teremos que aguardar uma resposta do servidor.

O que queremos é que essas alterações possam ser feitas em tempo real. É exatamente aí que entra o protocolo WebSockets.

Vamos comparar os protocolos HTTP e o WebSockets.

Representação da interação entre cliente e servidor no protocolo HTTP. À esquerda temos o Cliente e à direita temos o Servidor. Entre eles, ao centro, duas setas horizontais: primeira seta representa Requisição, ela sai de Cliente e aponta para Servidor; segunda seta representa Resposta, ela sai de Servidor e aponta para Cliente.

Nesta imagem temos o modelo de requisição e resposta do protocolo HTTP. Temos o cliente de um lado e o servidor do outro, e sempre acontece uma requisição do cliente para o servidor e, após um tempo de operações, o servidor devolve uma resposta para o cliente.

No protocolo HTTP:

Caso o cliente precise de outra informação do é preciso iniciar uma nova comunicação e esses processos acontecerão novamente.

Protocolo WebSockets

Representação da interação entre cliente e servidor no protocolo WebSockets. À esquerda temos o Cliente e à direita temos o Servidor. Entre eles, ao centro, duas setas horizontais, ambas representam Eventos, a primeira seta sai de Cliente e aponta para Servidor e a segunda seta sai de Servidor e aponta para Cliente.

Esta é a representação de comunicação do WebSockets. Nele não temos o modelo tradicional de requisição e resposta, teremos agora um modelo de comunicação baseado em eventos.

Então, teremos o cliente de um lado e o servidor do outro. Uma seta aponta do cliente para o servidor e uma seta aponta do servidor para cliente. Acima dessas setas temos o texto "Eventos".

Como acontecem esses eventos?

Basicamente, tanto o cliente quanto o servidor podem ficar "escutando" o tempo inteiro a emissão de algum evento. Por exemplo, o servidor pode acompanhar um evento de submissão de formulário, por exemplo, o servidor vai imediatamente capturar esse evento.

É um modelo de comunicação mais dinâmico e imediato. Não tem aquele atraso que costuma ter o modelo de requisição e resposta.

Outra coisa interessante é que sempre que o cliente se conectar ao servidor será criado um socket, uma conexão, para esse cliente e esse servidor. Para cada cliente conectado no servidor teremos um socket ativo.

Outra diferença é que tanto o cliente quanto o servidor podem emitir eventos. É o que chamamos de comunicação bidirecional. Diferente do modelo HTTP onde o cliente sempre inicia a conexão, no WebSockets tanto o cliente quanto o servidor podem emitir eventos independentemente de o outro ter emitido algum evento antes.

Visto isso, parece que esse protocolo WebSockets é exatamente a solução para o nosso caso fictício onde a Eduarda e a Juliana querem que seus textos estejam sempre em sincronia e querem ver as atualizações sendo feitas em tempo real na tela.

O WebSockets é mais útil nos casos em que queremos essa interação em tempo real, como acontece nos games online, por exemplo. Para os outros casos, onde o modelo HTTP já está sendo utilizado, podemos manter o HTTP, pois ele supre as nossas necessidades.

Estou ansioso para te mostrar como o WebSockets funciona na prática. Te espero nos próximos vídeos.

Criando o Alura Docs - Criando o servidor

Vamos começar a desenvolver as funcionalidades do AluraDocs que, por enquanto, só tem as partes estáticas prontas.

Na atividade anterior já disponibilizamos para você o projeto inicial com as duas páginas HTML. Estou com esse projeto aberto no meu VS Code.

Dentro desse projeto temos um arquivo .gitgnore, para ignorar a pasta node_modules. Isso é caso você utilize Git, vamos ignorar essa pasta na hora de subir o projeto.

Também temos a pasta "public", que é a pasta onde estão os dois arquivos HTML: index.html, nela estou utilizando Bootstrap para a estilização, e nesta pasta também temos o documento.html. Você pode dar uma olhada com calma nesses arquivos HTML.

Para conseguirmos utilizar o protocolo WebSockets precisamos ter o servidor Node rodando.

Para fazer o projeto em Node vamos abrir o terminal integrado do VS Code com o atalho "Ctrl + J". E, no terminal faremos o comando npm init -y, o "Y" serve para responder "sim" às perguntas que o terminal faz ao criarmos um novo projeto em Node:

npm init -y

Ao executar esse comando, foi criado o arquivo package.json na raiz do nosso projeto.

Feito isso, podemos instalar o Express, que utilizaremos para fazer um servidor Node básico. Vamos baixar a versão 4 do Express.

npm install expres@4

Após executar esse comando podemos fechar o terminal integrado.

Se abrirmos o package.json veremos na parte de dependências que o Express foi instalado com sucesso na nossa aplicação.

"dependencies": {
    "express": "^4.18.2"
}

Vou aproveitar que estou no package.json e vou adicionar, logo antes da parte de scripts, mais uma configuração de uma propriedade type com valor module para conseguirmos utilizar os módulos do ECMAScript para usarmos palavras-chaves como import e export.

  "name": "alura-docs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },

Vamos salvar o projeto, fechar o package.json e criar o arquivo do nosso servidor.

Na pasta raiz do projeto criaremos uma nova pasta chamada "src". Dentro da pasta "src" criaremos um arquivo chamado servidor.js. Começaremos importando o Express.

import express from "express";

Com isso, já conseguiremos criar um app do Express com a constante app recebendo express(). Em seguida vamos declarar a porta que vai receber process.env.porta ou 3000, colocaremos duas barras verticais (||) para indicar o "ou" do JavaScript.

import express from "express";

const app = express();
const porta = process.env.porta || 3000;

Agora podemos informar qual porta a app vai "escutar" com app.listen(), os parâmetros serão porta o segundo parâmetro será a função callback que pode executar um console.log() com uma template string informando que o servidor está escutando na porta, e faremos uma interpolação para inserir a constante porta ${porta}.

import express from "express";

const app = express();
const porta = process.env.porta || 3000;

app.listen(porta, () => console.log(`Servidor escutando na porta ${porta}`)

Agora precisamos adicionar um script em package.json após o script test. Adicionaremos o script dev e o valor dele será uma string com o valor node src/servidor.js.

"dev": "node src/servidor.js"
{
  "name": "alura-docs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "node src/servidor.js"
  },

Podemos salvar o projeto. Vamos abrir o terminal do VS Code e executar o comando npm run dev para executar esse script.

npm run dev

O retorno no terminal foi:

Servidor escutando na porta 3000

Nosso servidor já está funcionando. Agora, vamos fazer o nosso servidor mostrar as páginas HTML que estão na pasta "public" do nosso projeto.

Para isso, vamos fazer algumas configurações.

Primeiro, vamos escrever no início do arquivo servidor.js importando a url e o path:

import express from "express";
import url from "url";
import path from "path";

const app = express();
const porta = process.env.porta || 3000;

app.listen(porta, () => console.log(`Servidor escutando na porta ${porta}`)

Em seguida, abaixo de const porta vamos pegar o caminho atual para navegar até o diretório da pasta "public". Usaremos url.fileURLToPath, que é um método do módulo URL, com o parâmetro import.meta.url.

const caminhoAtual = url.fileURLToPath(import.meta.url);

Isso vai nos dar exatamente o caminho atual de onde estamos até o servidor.js. Queremos navegar até a pasta "public", então escreveremos em seguida um const diretorioPublico que vai receber path.join onde passaremos como primeiro parâmetro o caminhoAtual e o segundo parâmetro será uma string subindo dois níveis a partir do caminho atual "../..". No primeiro par de pontos vamos sair do arquivo atual e ir para o diretório atual, que é a pasta "src", e no segundo par de pontos vamos subir mais um nível e ir para a pasta raíz do projeto.

Estando na pasta raiz, queremos navegar para a pasta "public": "../..", "public").

const caminhoAtual = url.fileURLToPath(import.meta.url);
const diretorioPublico = path.join(caminhoAtual, "../..", "public");

E, ao chegar no diretório "public" podemos fazer app.use passando express.static como parâmetro e o parâmetro de static será o diretorioPublico.

const caminhoAtual = url.fileURLToPath(import.meta.url);
const diretorioPublico = path.join(caminhoAtual, "../..", "public");
app.use(express.static(diretorioPublico));

Com esta última linha, app.use(express.static(diretorioPublico)), queremos informar que desejamos que o Express utilize o diretório público de forma estática e vamos poder disponibilizá-los no navegador.

Vamos salvar o arquivo que ficou assim:

import express from "express";
import url from "url";
import path from "path";

const app = express();
const porta = process.env.porta || 3000;

const caminhoAtual = url.fileURLToPath(import.meta.url);

const caminhoAtual = url.fileURLToPath(import.meta.url);
const diretorioPublico = path.join(caminhoAtual, "../..", "public");
app.use(express.static(diretorioPublico));

app.listen(porta, () => console.log(`Servidor escutando na porta ${porta}`)

Agora vamos pausar o servidor e executá-lo novamente.

npm run dev

Servidor escutando na porta 3000

Em seguida, vamos para o navegador e inserir na barra de endereço a URL:

http://localhost:3000

E apareceu a página do AluraDocs! Nosso código funcionou corretamente. O servidor está mostrando no navegador.

Agora, vamos resolver aquele problema de ter que reiniciar o servidor sempre que fazemos alguma alteração no nosso projeto.

Para isso, utilizaremos a biblioteca nodemon, que vai nos ajudar a reiniciar o servidor automaticamente.

Podemos pausar o servidor com o comando ^C.

^C

E escreveremos o comando para instalar a versão 2 do nodemon e também vamos inserir um traço seguido de um "D" maiúsculo para instalar o nodemon como dependência de desenvolvimento, porque não queremos que essa dependência vá para produção, ela servirá apenas para nos auxiliar no desenvolvimento.

npm install nodemon@2 -D

Ao executar o comando o nodemon foi instalado. Podemos conferir no fim do arquivo package.json que o nodemon está instalado como dependência de desenvolvimento.

"devDependencies": {
    "nodemon": "^2.0.20"
  }

Por fim, para utilizar o nodemon de fato, vamos alterar o script dev, nele trocaremos "node" por "nodemon":

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon src/servidor.js"
  },

Feito isso, podemos salvar o projeto. E ao abrir o terminal integrado e escrever o comando npm run dev receberemos o retorno de algumas linhas indicando que o nodemon está funcionando e ao salvar o projeto o servidor vai reiniciar automaticamente. Isso vai facilitar o desenvolvimento.

A partir do próximo vídeo começaremos a implementar as primeiras funcionalidades do AluraDocs utilizando protocolo WebSockets.

Sobre o curso WebSockets: implemente comunicações em tempo real com Socket.IO e MongoDB

O curso WebSockets: implemente comunicações em tempo real com Socket.IO e MongoDB possui 185 minutos de vídeos, em um total de 53 atividades. Gostou? Conheça nossos outros cursos de Node.JS em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Node.JS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas