# Node js Express con MongoDB
WARNING
- Debe tener instalado Node.js (opens new window)
- Debe tener instalado MongoDB (opens new window) y tener ya un usuario y base creada click para la documentación (opens new window)
# 1. Creación del proyecto
- Cree una carpeta donde guste, esta contendrá el proyecto, por ejemplo:

- Dentro de la carpeta abriremos el cmd, y nos debe salir la siguiente ruta, debemos darnos cuenta que esté el nombre de la carpeta creada en el punto anterior

- Escribiremos el siguiente comando
mkdirseguido del nombre de la carpeta que tendrá el proyecto, por ejemplo:
mkdir proyecto

- Luego entraremos a la carpeta con
cdseguido del nombre que se le dió en el punto anterior
cd proyecto

- Estando dentro de nuestro proyecto, toca crear el archivo
package.json, pero no te preocupes, esto se lo crea con el siguiente comando:
npm init

- Luego nos solicitará algunos datos para configurar el proyecto, puedes darle enter omitiendo o puedes ingresar, como sea tu elección.

Con esto ya tenemos creado el proyecto, para abrirlo basta escribir code . para que se nos abra Visual Studio Code

Veremos únicamente el archivo json creado en puntos anteriores

# 2. Instalación de dependencias
- La primera dependencia que instalaremos será
express, y para ello podemos dijitar el siguiente comando en el cmd si aún no la has cerrado o abriendo el terminal en el Visual Studio Code
npm install express --save
cmd

Visual Studio Code

instalación

- Luego de la instalación veremos que nos aparece otro archivo
jsoneste tendrá las dependencias y la carpetanode_modulestendrá las carpetas de dichas dependencias

La segunda dependencia será la que nos permitirá conectarnos a la
mongoDb, podemos instalar- mongoose (opens new window)
npm install mongoose - mongodb (opens new window)
npm install mongodb
Elegiré la primera opción
- mongoose (opens new window)

Y puedes observar en package.json la nueva dependencia
- La tercera dependencia será
nodemon(opens new window) esta nos permitirá un ambiente de trabajo más fluido.
npm install nodemon

Luego, debemos hacer un pequeño cambio al package.json agregando al scripts lo siguiente:
"start": "nodemon app.js"
Y ese será el archivo que se reiniciará con cada cambio.

- La cuarta dependencia será
body-parser(opens new window) será para el middleware
npm install body-parser

# 3. Ejecución del proyecto
- Primero crearemos un archivo
app.jsdebe tener nombre dado cuando se instalónodemon. - Luego dentro del archivo escribieremos lo siguiente
// importamos express
const express = require('express');
// llamanos al función
const app = express();
// escuchamos el puerto 3000 y mostramos un mensaje por consola
app.listen(3000, () =>{
console.log('Conectado');
});
Y para ejecutar, en el terminal escribiremos
npm start
Y, listo 🤓 hemos ejecutado nuestro proyecto pero aún falta para hacerlo api-rest 🥴

# 4. Estructura del proyecto
La estructura será la siguiente
PROYECTO
- node_modules
- src
- app
- config
- controller
- repository
- service
- exception
- collection
- route
- app.js
- package-lock.json
- package.json
Dentro de la carpeta
configcrearemos un archivoserver.jsque contrendrá las credenciales del servidor y el puerto que escuchará nuestra aplicación.
/**
* BD: mongodb
* user: aprendiendo
* pass: 123456
* server: localhost
* port: 27017
* bd: pruebas
*/
module.exports = {
port : process.env.PORT || 3000, //puerto que escuchará nuestra aplicación
mongodb : process.env.MONGODB || 'mongodb://aprendiendo:123456@localhost:27017/proyecto'
}
- Dentro de la carpeta
exceptioncreamos un archivoexception.jsque contrendrá nuestras excepciones personalizadas, y estas son algunas, podemos tener más dependiendo la necesidad del proyecto.
// excepción al crear una colección
const create = (res, payload) => {
message(res, 201, payload, false);
}
// excepción al enviar una petición errónea
const badRequest = (res, payload) => {
message(res, 400, payload, true);
}
// excepción interna del proyecto
const internalError = (res, payload) => {
message(res, 500, payload, true);
}
// mensaje a devolver
function message(res, code, payload, flag){
res.status(code).json({"error": flag, "payload": payload??null});
}
// exportamos las excepciones para poder importarlas en otros archivos
module.exports = {
create,
badRequest,
internalError
}
- Dentro de la carpeta
collectioncrearemos nuestros modelos o esquemas de nuestra base, por esta práctica crearemos un sólo esquema persona y el archivo serápersonCollection.js.
// importamos mongoose para poder hacer uso del schema
const mongoose = require('mongoose');
// creamos nuestro esquema
const Person = mongoose.Schema({
name: String,
city: String
})
// creamos una constante de nuestro modelo para poderlo exportar
const Person = mongoose.model('Person', collectionPerson, 'Person');
// exportamos nuestro esquema
module.exports = Person;
- Dentro de la carpeta
repositorycrearemos el archivopersonRepository.jsy aquí haremos todo las setencias a nuestra base, es decir, es aquí donde guardaremos, buscaremos, actualizaremos y eliminaremos nuestros documentos.
// importamos nuestro esquema
const Person = require('../collection/personCollection.js');
// el método es async porque devuelve una promesa
const guardar = async (req) => {
const p = new Person(req.body);
return await p.save();
}
const buscar = async() =>{
return await Person.find();
}
const actualizar = async(req) =>{
return await Person.findByIdAndUpdate(
{
_id: req.params.id
},
{
$set:
{
name : req.body.name,
city : req.body.city
}
}
);
}
const eliminar = async(req) =>{
return await Person.findByIdAndDelete(
{
_id: req.params.id
}
);
}
// exporamos nuestro método para poder importarlo en nuestro servicio
module.exports = {
guardar,
buscar,
actualizar,
eliminar
}
- Dentro de la carpeta
servicecrearemos un archivopersonService.jses la parte media entre el controllador y repositorio, y es aquí donde se valida los datos, lanza excepciones y demás.
// importamos nuestro repositorio
const repository = require('../repository/personRepository.js');
// importamos nuestras excepciones
const exception = require('../exception/exception.js');
// esta función recibe el requerimiento (body) y respuesta (http)
function guardar(req, res){
try {
if(req.body.name == "" || req.body.name == null || req.body.city == "" || req.body.city == null)
// exception si los datos no son los esperados
exception.badRequest(res, "Ingrese los datos");
else{
repository.guardar(req)
.then(doc => {
// exception de creación
exception.success(res, "Datos ingresados");
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, err);
});
}
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
// esta función recibe el requerimiento (body) y respuesta (http)
function buscar(res){
try {
repository.buscar()
.then(doc => {
// exception de creación
if(doc.length > 0)
exception.found(res, doc);
else
exception.notFound(res, "No hay documentos que mostrar");
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, err);
});
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
// esta función recibe el requerimiento (body) y respuesta (http)
function actualizar(req, res){
try {
if(req.body.name == "" || req.body.name == null || req.body.city == "" || req.body.city == null)
// exception si los datos no son los esperados
exception.badRequest(res, "Ingrese los datos");
else{
repository.actualizar(req)
.then(doc => {
// exception de actualización
if(doc != null)
exception.success(res, "Documento actualizado");
else
exception.notFound(res, "No existe el documento");
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, "El id tiene un formato erróneo");
});
}
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
// esta función recibe el requerimiento (body) y respuesta (http)
function eliminar(req, res){
try {
if(req.params.id == "" || req.params.id == null )
// exception si los datos no son los esperados
exception.badRequest(res, "Ingrese los datos");
else{
repository.eliminar(req)
.then(doc => {
// exception de creación
if(doc != null)
exception.success(res, "Documento eliminado");
else
exception.notFound(res, "No existe el documento");
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, "El id tiene un formato erróneo");
});
}
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
// exportamos el método para poderlo importar en el controllador
module.exports = {
guardar,
buscar,
actualizar,
eliminar
}
- Dentro de la carpeta
controllercrearemos un archivopersonController.js, aquí llamaremos a todos los métodos de nuestro servicio persona.
// importamos nuestro servicio
const service = require('../service/personService.js');
// importamos nuestras excepciones
const exception = require('../exception/exception.js');
// método insertar
function insert(req, res){
try {
// llamamos a nuestro método
service.guardar(req, res);
} catch (error) {
// exception inesperada
exception.internalError(res, "Problema inesperado");
}
}
function select(req, res){
try {
// llamamos a nuestro método
service.buscar(res);
} catch (error) {
// exception inesperada
exception.internalError(res, "Problema inesperado");
}
}
function update(req, res){
try {
// llamamos a nuestro método
service.actualizar(req, res);
} catch (error) {
// exception inesperada
exception.internalError(res, "Problema inesperado");
}
}
function borrar(req, res){
try {
// llamamos a nuestro método
service.eliminar(req, res);
} catch (error) {
// exception inesperada
exception.internalError(res, "Problema inesperado");
}
}
module.exports = {
insert,
select,
update,
borrar
}
- Dentro de la carpeta
routecrearemos un archivopersonRoute.jsque contrendrá las rutas de nuestros endpoints de persona.
// importamos express
const express = require('express');
// hacemos uso de la función Router()
const api = express.Router();
// importamos nuestro controlador
const personCroller = require('../controller/personController.js');
// hacemos uso de los métodos http
api.post('/add',personCroller.insert);
api.get('/select', personCroller.select);
api.put('/update/:id/' , personCroller.update);
api.delete('/delete/:id',personCroller.borrar);
// exportamos api
module.exports = api;
- Dentro de la carpeta
appcrearemos un archivoapp.jsque contrendrá o hará de almacenar todos los accesos a las rutas de nuestraapi-rest
// importamos express
const express = require('express');
// importamos body-parser
const bodyParser = require('body-parser');
// llamanos al función
const app = express();
// importamos nuestro archivo que contiene las rutas o endpoints de persona
const api = require('../route/personRoute.js');
// hacemos uso de body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// hacemos uso de nuestra ruta de persona
app.use('/api', api);
/* si tuvieramos más rutas de otras collections haríamos todo como se hiso con persona
* y aquí haríamos udo de la ruta por ejemplo
* app.use('/api', api2);
*/
// exportamos app para llamarlo en nuestro archivo app.js que está en la raíz de nuestro proyecto
module.exports = app;
Teniendo lista la estructura con sus archivos correspondientes, ahora toca modificar el archivo app.js que está en la raíz del proyecto para acceder a la base y modificar el escuchar nuestra aplicación.
// importamos mongoose para la base
const mongoose = require('mongoose');
// importamos app
const personApp = require('./src/app/app.js');
// importamos la configuración del servidor
const server = require('./src/config/server.js');
// nos conectamos al la base
mongoose.connect(server.mongodb);
//creamos una constante de la connection
const connection = mongoose.connection;
// mostramos un console si ha fue exitosa
connection.once('open', () => {
console.log('MongoDb success');
});
// mostramos un console si ha fue errónea
connection.on('error', (err) => {
console.log('Echale agua para que encienda', err.message);
});
// escuchamos el puerto
personApp.listen(server.port, () =>{
console.log('Conectado');
});
Proyecto terminado

Dame click para ver la ejecución
Dame click para descargar el proyecto (opens new window)
# 5. Encripta la contraseña de tu usuario
Para esta práctica vale tener un schema que haga referencia a usuarios, sin embargo por motivo de práctica, aumentaremos un campo pass al schema person y quedaría de la siguiente forma:
// importamos mongoose para poder hacer uso del schema
const mongoose = require('mongoose');
// creamos nuestro esquema
const collectionPerson = mongoose.Schema({
name: String,
city: String,
pass: String
})
// creamos una constante de nuestro modelo para poderlo exportar
const Person = mongoose.model('Person', collectionPerson);
// exportamos nuestro esquema
module.exports = Person;
De igual manera debemos validar que al ingresar una documento, este campo esté lleno y el cambio quedaría de la siguiente forma:
function guardar(req, res){
try {
if(req.body.name == "" || req.body.name == null ||
req.body.city == "" || req.body.city == null ||
req.body.pass == "" || req.body.pass == null)
// exception si los datos no son los esperados
exception.badRequest(res, "Ingrese los datos");
else{
repository.guardar(req)
.then(doc => {
// exception de creación
exception.success(res, "Datos ingresados");
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, err);
});
}
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
Teniendo listo los cambios, ahora debemos elegir una dependencia que cumpla con la encriptación, hay varias, sos libre de elegir la que mejor te parezca, y bueno yo he instalado la siguiente cripto-js (opens new window)
npm install crypto-js
Ahora solo queda encriptar la contraseña, ¿Pero cómo 🤔?. Presta atención
// importamos
const CryptoJS = require("crypto-js");
// nuestra contraseña
const pass = "123456";
// nuestra palabra clave de encriptación
const secretKey = "Aprendiendo";
// encriptar
const passCrypto = CryptoJS.AES.encrypt(pass, secretKey).toString();
// mostrar
console.log(passCrypto);//salida => U2FsdGVkX18jpRlY5yNjiuyBSdbjPo3EjzaGBsdiEa4=
Viste?, súper fácil, ahora solo basta acomodar eso en el servicio y listo.
TIP
Configura tu secretKey en config
// importamos nuestro repositorio
const repository = require('../repository/personRepository.js');
// importamos nuestras excepciones
const exception = require('../exception/exception.js');
// importamos config
const server = require('../config/server.js');
// importamos
const CryptoJS = require("crypto-js");
// esta función recibe el requerimiento (body) y respuesta (http)
function guardar(req, res){
try {
if(req.body.name == "" || req.body.name == null ||
req.body.city == "" || req.body.city == null ||
req.body.pass == "" || req.body.pass == null)
// exception si los datos no son los esperados
exception.badRequest(res, "Ingrese los datos");
else{
req.body.pass = CryptoJS.AES.encrypt(req.body.pass, server.secretKey).toString();
repository.guardar(req)
.then(doc => {
// exception de creación
onst token = {
"token": t.createToken(doc)
}
// enviamos el token
exception.success(res, "Datos ingresados",token);
})
.catch(err => {
// exception si hubo algo inesperado con la solicitud
exception.badRequest(res, err);
});
}
} catch (error) {
// exception interna del programa
exception.internalError(res, "Problema inesperado");
}
}
Dame click para ver la encriptación
# 7. Desencripta la contraseña de tu usuario
Esto super sencillo, basta con una línea, te daré la línea pero es tu deber saber donde lo colocas, te mostraré la ejecución con un console.log(); descriptando la contraseña del paso 6 que es Ecuado2021.
// consultamos de nuestra base la contraseña encriptada
const passCryto = "U2FsdGVkX1/rxCuneD4XFDTkILTnTa0xx0HfJUPtURQ="; //la puedes ver en la clave en Pruebas
// nuestra palabra clase de desencriptación
const secretKey = "Aprendiendo-con-Guillermo"; // esta clave está en mi config, recuerda hacer ese cambio
// desencriptar
const passOriginal = CryptoJS.AES.decrypt(passCryto, secretKey);
// mostrar
console.log(passOriginal.toString(CryptoJS.enc.Utf8));//salida => Ecuador2021
# 6. Dale seguridad a tu Api con JWT
Para darle seguridad a nuestra api usaremos jwt (opens new window) y se compone de tres partes:
- Header o cabecera
- Payload o carga útil
- Signature
Primero que tenemos que hacer es instalar la dependencia jwt-simple (opens new window), y dayjs (opens new window) de igual manera, puedes usar la que mejor te parezca
npm install jwt-simple
npm install dayjs
Ver documentación de dayjs (opens new window)
Segundo es determinar la clave que se usará para cifrar tu token, recuerda que mientras más extensa, más segura será.
/**
* BD: mongodb
* user: aprendiendo
* pass: 123456
* server: localhost
* port: 27017
* bd: pruebas
*/
module.exports = {
port : process.env.PORT || 3000, //puerto que escuchará nuestra aplicación
mongodb : process.env.MONGODB || 'mongodb://aprendiendo:123456@localhost:27017/proyecto',
secretKey : process.env.SECRET_KEY || 'Aprendiendo-con-Guillermo',
secretToken : process.env.SECRET_TOKEN || '@pr3nd13nd0c0nGu1ll3rm@'
}
Tercero será reestructurar nuestro proyecto de la siguiente forma:

Cuarto será crear y descodificar nuestro token, para esto nos iremos a tokenService.js y escribiremos los siguiente:
// importaciones
const jwt = require('jwt-simple');
const Day = require('dayjs');
const server = require('../../config/server.js');
// creación del token
const createToken = (doc) => {
// creamos el payload de nuestro token
const payload = {
// información del token
sub: doc._id, // no se recomienda colocar el id, pero es un ejemplo
// creacion token
iat: Day().unix(),
// expirar token
p: Day().add(1, 'm').unix() // m -> minuto <- por ejemplo
}
/** Podemos usar
* HS256
* HS384
* HS512
*/
return jwt.encode(payload, server.secretToken, 'HS256');
}
// decodificación del token
const decodeToken = (token) => {
// creamos una promesa
const decode = new Promise((res, err) => {
try{
// decoficamos el token
const payload = jwt.decode(token, server.secretToken, 'HS256');
// verificamos si no ha expirado
if(payload.exp <= Day().unix())
err({
message: 'Su sesión ha expirado'
})
// devolvemos algo de ser necesario, para indicar que todo está correcto
res(payload._id)
}catch(e){
// en caso de que el token no se pueda decodificar
err({
message: 'Tokén inválido'
})
}
})
return decode;
}
Quinto en el archivo authorization.js importaremos a nuestro servicio de token para determinar y dar acceso al recurso solicitado si este tiene permiso, caso contrario le mandamos una excepción (debes agregarla 😉)
// importamos
const exception = require('../exception/exception.js');
const tokenService = require('../service/token/tokenService.js');
// creamos el método que recibe el requerimiento, el result y el next para dar paso al recurso
const authorization = (req, res, next) => {
/** este if es para hacer público nuestro endpoint http://localhost:3000/api/add
* puedes usar un arreglo, si deseas liberar más enpoint
*/
if(req.path.replace ('/', '') == 'add')
next(); // continua con el recurso solicitado
else{
// verificamos si la solicitud tiene un token
if(!req.headers.authorization){
// muestra una excepción
exception.forbidden(res, "No tiene permiso");
}else{
// obtenemos el token
const token = req.headers.authorization;
// llamamos al método que decofica el token
tokenService.decodeToken(token)
.then(res => {
next() // continua con el recurso solicitado
})
.catch(err => {
// muestra una excepción ya sea por token inválido o sesión expirada
exception.unauthorized(res, err.message);
})
}
}
}
// exportamos
module.exports = authorization;
Sexto debemos enviarle el token al cliente para que este lo almacene y nos lo envíe en cada solicitud, para esto debemos hacer un pequeño cambio en nuestro personService.js y quedaría de la siguiente manera.
// importamos nuestro token
const token = require('../services/token/token.js');
// dentro del then invocamos nuestro servicio
.then(doc => {
// guardamos nuestro token
const token = {
"token": tokenService.createToken(doc)
}
// exception de creación y enviamos el token
exception.success(res, "Datos ingresados",token);
})
Septimo, ahora solo queda implementar nuestro middleware, y ¿dónde lo implementamos 🤔?, puedes ya sea en personRoute.js o en app.js.
Pensemos, si colocamos en personRoute.js, tenemos que colocar nuestro middleware en cada endpoint, sin embargo, si lo colocamos en app.js basta con colocarlo despúes del nuestro de nuestra api, de todos modos ten las dos formas.
personRoute.js
// importamos express
const express = require('express');
// hacemos uso de la función Router()
const api = express.Router();
// importamos nuestro controlador
const personCroller = require('../controller/personController.js');
// importamos nuestro middleware
const authorization = require('../middleware/authorization.js');
// hacemos uso de los métodos http
api.post('/add', authorization, personCroller.insert);
api.get('/select', authorization, personCroller.select);
api.put('/update/:id/' , authorization, personCroller.update);
api.delete('/delete/:id', authorization, personCroller.borrar);
// exportamos api
module.exports = api;
app.js
// importamos express
const express = require('express');
// importamos body-parser
const bodyParser = require('body-parser');
// llamanos al función
const app = express();
// importamos nuestro archivo que contiene las rutas o endpoints de persona
const api = require('../route/personRoute.js');
// importamos nuestro middleware
const authorization = require('../middleware/authorization.js');
// hacemos uso de body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// hacemos uso de nuestra ruta de persona
app.use('/api', authorization, api);
/* si tuvieramos más rutas de otras collections haríamos todo como se hiso con persona
* y aquí haríamos udo de la ruta por ejemplo
* app.use('/api', api2);
*/
// exportamos app para llamarlo en nuestro archivo app.js que está en la raíz de nuestro proyecto
module.exports = app;
Dame click para ver la ejecución implemtando app.js
Dame click para descargar el proyecto (opens new window)