Original article: How to build a real time chat application in Node.js using Express, Mongoose and Socket.io

En este tutorial, utilizaremos la plataforma Node.js para crear una aplicación de chat en tiempo real que envíe y muestre mensajes a un destinatario al instante sin actualizar la página. Usaremos el framework de JavaScript Express.js y las bibliotecas Mongoose y Socket.io para lograr esto.

Antes de comenzar, echemos un vistazo rápido a los conceptos básicos de Node.js

Node.js

Node.js es un entorno de tiempo de ejecución de JavaScript, de código abierto y multiplataforma que ejecuta código JavaScript fuera del navegador. La ventaja más importante de usar Node es que podemos usar JavaScript como lenguaje tanto de front-end como de back-end.

Como sabemos, JavaScript se usó principalmente para secuencias de comandos del lado del cliente, en las que las secuencias de comandos se incrustaron en el HTML de una página web y se ejecutaron en el lado del cliente mediante un motor de JavaScript en el navegador web del usuario.

Node.js permite a los desarrolladores usar JavaScript para escribir herramientas de línea de comandos y para secuencias de comandos del lado del servidor —ejecutando secuencias de comandos del lado del servidor para producir contenido de página web dinámico antes de que la página se envíe al navegador web del usuario.

Para instalar node:

https://nodejs.org/es/download/

Aunque el node tiene un solo subproceso, aún es más rápido usar funciones asíncronas. Por ejemplo, Node puede procesar otras cosas mientras se lee un archivo del disco o mientras se espera que se complete una solicitud HTTP. El comportamiento asincrónico se puede implementar mediante devoluciones de callback. Además, JavaScript funciona bien con bases de datos JSON y No-SQL.

Módulos NPM

Nodejs permite incluir en la aplicación los módulos de las librerías. Estos módulos pueden ser módulos definidos por el usuario o de terceros.

Los módulos de terceros se pueden instalar con el siguiente comando:

npm install nombre_del_módulo

y los módulos instalados se pueden usar usando la función require():

var módulo = require(‘nombre_del_módulo’)

En las aplicaciones de Node, usaremos un archivo package.json para mantener las versiones del módulo. Este archivo se puede crear con este comando:

npm init

y los paquetes deben instalarse de la siguiente manera:

npm install -s nombre_del_módulo

Hay muchos frameworks que se pueden agregar como módulos a nuestra aplicación Node. Estos se explicarán más adelante según sea necesario.

Aplicación de Chat Simple

La aplicación debe permitir que varios usuarios chateen juntos. Los mensajes deben actualizarse sin refrescar la página. Para simplificar, evitaremos la parte de autenticación.

Podemos empezar por crear un nuevo directorio de proyecto y pasar a él. Luego podemos iniciar nuestro proyecto con el siguiente comando:

npm init

Esto nos pedirá que ingresemos detalles sobre nuestro proyecto.

Después de esto, se creará un archivo package.json:

{
 “name”: “test”,
 “version”: “1.0.0”,
 “description”: “”,
 “main”: “index.js”,
 “scripts”: {
 “test”: “echo \”Error: no test specified\” && exit 1"
 },
 “author”: “”,
 “license”: “ISC”
}

Nuestro directorio de aplicaciones ya está configurado.

Lo primero que necesitamos crear es un servidor. Para crear eso, utilizaremos un framework llamado Express.

Express.js

Express.js, o simplemente Express, es un framework de aplicación web para Node.js. Express ofrece un sólido conjunto de características para aplicaciones web y móviles. Express ofrece una capa delgada de características fundamentales de aplicaciones web, sin encubrir las características de Node.js.

Instalaremos Express.js usando el siguiente comando:

npm install -s express

Dentro del archivo package.json se agregará una nueva línea:

dependencies”: {
 “express”: “⁴.16.3”
 }

A continuación, crearemos un archivo server.js.

En este archivo necesitamos requerir Express y crear una referencia a una variable desde una instancia de Express. Los contenidos estáticos como HTML, CSS o JavaScript se pueden servir usando express.js:

var express = require(‘express’);

var app = express();

y podemos comenzar a escuchar un puerto usando el código:

var servidor = app.listen(3000, () => {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});

Ahora necesitamos crear un archivo HTML index.html que muestre nuestra interfaz de usuario. He agregado bootstrap y JQuery cdn.

//index.html

<!DOCTYPE html>
<html>
<head>
 <! — incluir bootstrap y jquery cdn →
</head>
<body>
<div class=”container”>
 <br>
 <div class=”jumbotron”>
 <h1 class=”display-4">Enviar mensaje</h1>
 <br>
 <input id = “nombre” class=”form-control” placeholder=”Nombre”>
 <br>
 <textarea id = “mensaje” class=”form-control” placeholder=”Su mensaje aquí”>
</textarea>
 <br>
 <button id=”enviar” class=”btn btn-success”>Enviar</button>
 </div>
 <div id=”mensajes”>
 
</div>
</div>
<script>

</script>
</body>
</html>

Tenga en cuenta que la etiqueta vacía <script> <;/script> será el lugar en el que escribiremos el código JavaScript del lado del cliente.

Para decirle a Express eso, usaremos un archivo estático. Agregaremos una nueva línea dentro de server.js:

app.use(express.static(__dirname));

Nosotros podemos ejecutar el server.js usando el comando:

node ./server.js

O un paquete llamado nodemon, para que los cambios realizados en el código sean detectados automáticamente. Descargaremos nodemon usando el comando:

npm install -g nodemon

-g — global, para que sea accesible en todos los proyectos.

Ejecutaremos el código usando el comando:

nodemon ./server.js

Si vas a localhost:3000 podemos ver el archivo de index:

caxmtV7tYzJ1EUU69TeX4YQVsC69EhgzcSL5
index.html

Ahora que nuestro servidor está funcionando, necesitamos crear nuestra base de datos. Para esta aplicación, tendremos una base de datos No-SQL y usaremos Mongodb. Estoy configurando mi mongodb en mongodb.com. Nuestra base de datos contendrá una única colección llamada mensajes con los campos nombre y mensaje.

UWJYcDmpxrFhUoKRCrgkhtaTcBD4z4NivreC

Para conectar esta base de datos a la aplicación, usaremos otro paquete llamado Mongoose.

Mongoose

Mongoose es una herramienta de modelado de objetos MongoDB diseñada para trabajar en un entorno asíncrono. Mongoose se puede instalar usando el comando:

npm install -s mongoose

Dentro de server.js necesitaremos mongoose:

var mongoose = require(‘mongoose’);

Y le asignaremos una variable, la URL de nuestra base de datos mongodb:

var dbUrl = ‘mongodb://username:pass@ds257981.mlab.com:57981/simple-chat’

Mongoose se conectará a la base de datos mongodb con el método de conexión:

mongoose.connect(dbUrl , (err) => { 
   console.log(‘Mongodb conectado’,err);
})

Y definiremos nuestro modelo de mensaje como:

var Mensaje = mongoose.model(‘Mensaje’,{ nombre : String, mensaje: String})

Podemos implementar la lógica de chat ahora. Pero antes de eso, hay un paquete más que debe agregarse.

Body-Parser

Body-Parser extrae la parte del cuerpo completo de una secuencia de solicitud entrante y la expone en req.body. El middleware formaba parte de Express.js anteriormente, pero ahora debe instalarlo por separado.

Instálalo usando el siguiente comando:

npm install -s body-parser

Agregue los siguientes códigos a server.js:

var bodyParser = require(‘body-parser’)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))

Enrutamiento

El enrutamiento se refiere a cómo los puntos finales de una aplicación (URIs) responden a las solicitudes de los clientes. Usted define el enrutamiento usando métodos del objeto de aplicación Express que corresponden a métodos HTTP: app.get() para manejar solicitudes GET y app.post() para manejar solicitudes POST.

Estos métodos de enrutamiento especifican una función de callback (a veces denominada "funciones de controlador") que se activa cuando la aplicación recibe una solicitud para la ruta (punto final) y el método HTTP especificados. En otras palabras, la aplicación "escucha" las solicitudes que coinciden con las rutas y los métodos especificados, y cuando detecta una coincidencia, llama a la función de callback especificada.

Ahora necesitamos crear dos rutas a los mensajes para que nuestro chat funcione.

Dentro de server.js:

get: obtendrá todos los mensajes de la base de datos

app.get('/mensajes', (req, res) => {
  Mensaje.find({},(err, mensajes)=> {
    res.send(mensajes);
  })
})

post : publicará nuevos mensajes creados por el usuario en la base de datos

app.post('/mensajes', (req, res) => {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =>{
    if(err)
      sendStatus(500);
    res.sendStatus(200);
  })
})

Para conectar estas rutas al front-end, debemos agregar el siguiente código en la etiqueta del script del lado del cliente en index.html:

$(() => {
    $("#enviar").click(()=>{
       enviarMensaje({
          nombre: $("#nombre").val(), 
          mensaje:$("#mensaje").val()});
        })
      obtenerMensajes()
    })
    
function agregarMensajes(mensaje){
   $(“#mensajes”).append(`
      <h4> ${mensaje.nombre} </h4>
      <p>  ${mensaje.mensaje} </p>`)
   }
   
function obtenerMensajes(){
  $.get(‘http://localhost:3000/mensajes', (data) => {
   data.forEach(agregarMensajes);
   })
 }
 
function enviarMensaje(mensaje){
   $.post(‘http://localhost:3000/mensajes', mensaje)
 }

Aquí, enviarMensaje se usa para invocar la ruta de publicación de los mensajes y guardar un mensaje enviado por el usuario. El mensaje se crea cuando un usuario hace clic en el botón enviar.

De manera similar, obtenerMensajes se usa para invocar la ruta de obtención de mensajes. Esto hará que todos los mensajes se guarden en la base de datos y se agregarán al div de mensajes.

m1tJ6aV53XnmvkU8PjY7u16wkI1gKrplYWHo

El único problema ahora es que no hay forma de que el cliente sepa si el servidor está actualizado. Entonces, cada vez que publicamos un mensaje, debemos actualizar la página para ver los nuevos mensajes.

Para solucionar esto podemos añadir un sistema de notificaciones push que enviará mensajes del servidor al cliente. En Node.js usamos socket.io.

Socket.io

Socket.IO es una biblioteca de JavaScript para aplicaciones web en tiempo real. Permite la comunicación bidireccional en tiempo real entre los clientes web y el servidor. Tiene dos partes: una biblioteca del lado del cliente que se ejecuta en el navegador y una biblioteca del lado del servidor para Node.js. Socket.io permite la comunicación bidireccional basada en eventos en tiempo real.

Para instalar socket.io:

npm install -s socket.io

también necesitamos un paquete HTTP para que funcione Socket.io:

npm install -s http

Agregue el siguiente código a server.js:

var http = require(‘http’).Server(app);
var io = require(‘socket.io’)(http);

Y podemos crear una conexión:

io.on(‘connection’, () =>{
 console.log(‘Un usuario esta conectado’)
})

En el index.html agregue la siguiente etiqueta:

<script src=”/socket.io/socket.io.js”></script>

Ahora necesitamos crear una acción de emisión cuando se crea un mensaje en server.js. Así que la ruta de publicación se convierte en esto:

app.post('/mensajes', (req, res) => {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =>{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})

Y en la etiqueta del script del lado del cliente en index.html, agregue el siguiente código:

var socket = io();

socket.on(‘mensaje’, agregarMensajes)

Entonces, cada vez que se publica un mensaje, el servidor actualizará los mensajes en el div de mensajes.

6KUYtaL4L3ShtPNaHRKWXvP6v3mMuUAdq6R0

¡¡Gran!!

Esta es una aplicación muy básica que podemos crear en Node.js. Hay muchas posibilidades de mejora. El código terminado se puede encontrar en https://github.com/amkurian/simple-chat

server.js

var express = require('express');
var bodyParser = require('body-parser')
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(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))

var Mensaje = mongoose.model('Mensaje',{
  nombre : String,
  mensaje : String
})

var dbUrl = 'mongodb://username:password@ds257981.mlab.com:57981/simple-chat'

app.get('/mensajes', (req, res) => {
  Mensaje.find({},(err, mensajes)=> {
    res.send(mensajes);
  })
})

app.get('/mensajes', (req, res) => {
  Mensaje.find({},(err, mensajes)=> {
    res.send(mensajes);
  })
})

app.post('/mensajes', (req, res) => {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =>{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})

io.on('connection', () =>{
  console.log('Un usuario esta conectado')
})

mongoose.connect(dbUrl ,{useMongoClient : true} ,(err) => {
  console.log('Mongodb conectado',err);
})

var servidor = http.listen(3001, () => {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});

Espero que esto haya sido útil para comprender algunos conceptos básicos.

Algunos enlaces útiles

Socket.IO
SOCKET.IO 2.0 IS HERE FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE ~/Projects/tweets/index.js var io =…socket.io

Express - Node.js web application framework
Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and…expressjs.com

http://mongoosejs.com/