

EXPRESS.ROUTER()
&
COMMONJS


EXPRESS.ROUTER()
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
Repaso Live Coding
SIN routers
var express = require('express')
var app = express()
var users = [];
app.get('/', function (req, res) {
res.json(users);
})
app.get('/:id', function (req, res) {
const id = req.params.id;
const user = users.find(u => u.id == id);
return res.json(user)
})
app.listen(5000)
server.js
const express = require('express');
const app = express();
app.use(express.json());
const usersRouter = require('./api/users');
app.use('/api/users', usersRouter);
app.listen(5000);
server.js
ROUTER
var router = require('express').Router()
var users = [];
router.get('/', function (req, res) {
res.json(users);
})
router.get('/:id', function (req, res) {
const id = +req.params.id;
const user = users.find(u => u.id === id);
return res.send(user)
})
module.exports = router
/api/users/index.js
Ahora nuestro server.js o index.js
const express = require('express');
const app = express();
// Resources routers
const usersRouter = require('./api/users');
// Applying middlewares and routes
app.use(express.json());
app.use('/api/users', usersRouter);
app.listen(5000);
¿Qué estamos ganando?
- Código mucho más fácil de mantener.
- Un fichero de comportamientos por cada recurso y no todo en un index.js o server.js
- Poder dividir el trabajo en equipo.
- Poder más tarde testear cada router por separado.
- Un largo etcétera de beneficios creanme.

var axios = require('axios');
var cheerio = require('cheerio');
...
module.exports = {
getHTML : useAxiosToExtractDOM,
extractInfo : parseDOMToDataUsingCheerio
}
function useAxiosToExtractDOM(url) { }
function parseDOMToDataUsingCheerio(html) { }
utils/extractor.js
var app = require('express')();
var extractor = require('./utils/extractor');
app.get('/extractInfo', (req, res) => {
const url = req.queryParams.url;
extractor.getHTML(url)
.then(extractor.extracInfo)
.then( data => res.json(data))
}
server.js
var axios = require('axios');
var cheerio = require('cheerio');
...
module.exports = {
getHTML : useAxiosToExtractDOM,
extractInfo : parseDOMToDataUsingCheerio
}
router + module.exports
const router = require('express').Router();
router.get('/', ( req, res) => {
// Code here
});
router.get('/:id', ( req, res) => {
// Code here
});
router.post('/', ( req, res) => {
// Code here
});
module.exports = router;
api/users/index.js
Creamos el router en un fichero a parte y lo exportamos
router + module.exports
const express = require('express');
const app = express();
// Resources routers
const usersRouter = require('./api/users');
app.use('/api/users', usersRouter);
server.js
const router = require('express').Router();
router.get('/', ( req, res) => {
// Code here
});
router.get('/:id', ( req, res) => {
// Code here
});
router.post('/', ( req, res) => {
// Code here
});
module.exports = router;
api/users/index.js
Ponemos esto en práctica
Ejercicio en directo
Refactorizamos el ejercicio de ayer de la todo list
Refactorizamos el ejercicio de ayer de la api de twitter
¡ More cleaning code !

Y si ...
const router = require('express').Router();
const magic = require('./whereTheMagicHappens');
router.get('/', magic.doWhatever);
router.get('/:id', magic.doWhatever);
router.post('/', magic.doWhatever);
module.exports = router;
/api/users/index.js
Y si ...

Y si ...
index.js 10 líneas
api/users/index.js 8 líneas



api/users/users.controller.js 60 líneas
Ponemos esto en práctica
Live coding
¡A trabajar otra vez!
Primera API con 2 recursos
Queremos desarrollar una api restful con node para un proyecto copia de twitter. Aunque de momento, será solo una primera versión con usuarios y tweets como si fuese un blog personal.
USUARIOS
username* : string<uniq>
name? : string
email* : string
tweetsIDs : string[]
TWEETS
id* : string<uniq>
text : string
owner : string<ID>
createdAt : timestamp
Esto sería un id de los tweets que este usuario había creado
"2 tablas"
Primera API
- Deberán estar implementadas las funcionalidades de:
- Crear un nuevo usuario
- Borrar un usuario
- Editar el email de un usuario o el nombre (PATCH)
- Subir un tweet nuevo por parte de un usuario
- Ir a buscar un tweet en concreto por su id
- Borrar un tweet por su id
- *Opcional: Obtener todos los tweets ordenados tanto asc como desc por la fecha de subida
- *Opcional: Guardar los tweets y los usuarios en un fichero db.json y actualizarlo con cada cambio.
- OBLIGATORIO: Usar router para cada recurso
OJO ! CONTROLA QUE LA API NO SE PUEDA QUEDAR PILLADA EN NINGÚN MOMENTO, controla campos vacíos, request inválidas, etc etc y devuelve el error en la respuesta y el código correcto para dicho caso
PERSISTENCIA DE NUESTROS DATOS
Esta vez, no en ficheros, sino en una base de datos
SQL
NO-SQL
GRAFOS
¿ WHY MONGO?
Base de datos basada en documentos
Nos permite guardar la información como si de un objeto se tratase.
Los documentos del mismo tipo no están obligados a tener unos campos si o si e incluso estos podrán variar
EJEMPLO


DESCARGAMOS E INSTALAMOS
MONGODB
Si todo ha ido bien ...
Ejecutamos en una terminal
mongod o la ruta completa al .exe
y nos dirá que está listo y escuchando en el puerto 27017
Si queremos acceder a la consola
Para acceder a la consola de mongo una vez tengamos el mongod corriendo debemos de ejecutar el comando/ejecutable mongo
¡ AL LÍO !

Alternativas a la consola
Conectando mongo con nodejs
Librerías ODM
Hay módulos que nos permiten interacturar con los Documentos y collecciones de nuestra base de datos como si de objetos y arrays normales se tratasen :O
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todolist');
var TODOschema = mongoose.Schema({
text: String,
id : String,
createdAt : Number,
isCompleted : Boolean
});
var TODO = mongoose.model('todo', TODOschema);
TODO.find({}, (err, res) => {
console.log(res);
})
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todolist');
var TODOschema = mongoose.Schema({
text: String,
id : String,
createdAt : Number,
isCompleted : Boolean
});
var TODO = mongoose.model('todo', TODOschema);
TODO.find({}, (err, res) => {
console.log(res);
})
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todolist');
var TODOschema = mongoose.Schema({
text: String,
id : String,
createdAt : Number,
isCompleted : Boolean
});
var TODO = mongoose.model('todo', TODOschema);
TODO.find({}, (err, res) => {
console.log(res);
})
var TODO = mongoose.model('todo', TODOschema);
TODO.find({})
TODO.find({createdAt : 1521713274870})
TODO.find({createdAt : { $gt : 1521713274870} })
TODO.find({ otros : { $in : [ {hola : "mundo" } ]} })
// Proyecciones
TODO.find({createdAt : 1521713274870}, "text createdAt" )
Person.
find({
occupation: /host/,
'name.last': 'Ghost',
age: { $gt: 17, $lt: 66 },
likes: { $in: ['vaporizing', 'talking'] }
})
.limit(10)
.sort({ occupation: -1 })
.select({ name: 1, occupation: 1 })
.exec(callback);
// Using query builder
Person.
find({ occupation: /host/ })
.where('name.last').equals('Ghost')
.where('age').gt(17).lt(66)
.where('likes').in(['vaporizing', 'talking'])
.limit(10)
.sort('-occupation')
.select('name occupation')
.exec(callback);
var TODO = mongoose.model('todo', TODOschema);
var nuevo = new TODO({
text : 'Hello',
id : "asd",
createdAt : 13131312313,
isCompleted : false
})
nuevo.save();
Insertando documentos
TODO.create({ text: 'hola' }, function (err, small) {
if (err) return res.status(500).json(err);
// saved!
});
TODO.create({ text: 'hola' }).then(doc) {
// confirmed
});
Insertando documentos
TODO.create({ text: 'hola' }).then(doc) {
// confirmed
});
var TODO = mongoose.model('todo', TODOschema);
TODO.findOne ( { "text" : "hola" } , (err , doc) => {
doc.text = 'Nuevo texto';
doc.save();
}
Actualizando documentos
var TODO = mongoose.model('todo', TODOschema);
TODO.findOne ( { "text" : "hola" })
.update( { "text" : "adios" } )
.exec()
var TODO = mongoose.model('todo', TODOschema);
TODO.findOne ( { "text" : "hola" } , (err , doc) => {
doc.remove();
}
Borrando documentos
var TODO = mongoose.model('todo', TODOschema);
TODO.findOne( { "text" : "hola" })
.remove()
Borrando documentos
Sigamos

Vamos a cobrar más

Vamos a cobrar más
const TODOModel = require('./todos.model');
function getAllTODOs(req, res) {
TODOModel.find()
.then(response => {
console.log(response);
res.json(response);
})
}
Fichero : /api/todos/todos.controller.js
Vamos a cobrar más
const TODOModel = require('./todos.model');
function getTODOById(req, res) {
TODOModel.findOne({ id : req.params.id})
.then(response => {
res.json(response);
})
}
Fichero : /api/todos/todos.controller.js
Vamos a cobrar más
const TODOModel = require('./todos.model');
function getTODOById(req, res) {
TODOModel.findById(req.params.id)
.then(response => {
res.json(response);
})
.catch(err => {
res.json(err);
})
}
Fichero : /api/todos/todos.controller.js
SI USAMOS LOS _ID de mongo quedaría así
RESUMEN
async function resumenDeTodo( req, res ){
// Buscar por el ID
const encontrado = await model.findById(req.params.id)
// Insertar nuevos
const insertado = await model.create(req.body)
// Buscar por algún campo
const encontrados = await model.find({ name : req.params.name})
// Borrar por el ID
const borradoPorId = await model.findByIdAndRemove(req.params.id)
// Encontrar y editar por el ID
const borradoPorNombre = await model.findByIdAndUpdate(req.params.id , req.body)
}
También son promesas
Vamos a cobrar más
A currar
Guarda tus datos del proyecto de todolist en mongodb y usa mongoose para conectar tu api con la base de datos. NO HAGAS VALIDACIONES
¡UN PASO MÁS ALLÁ !

MONGOOSE TE PERMITE PONER VALIDACIONES
const mongoose = require('mongoose');
var TODOschema = mongoose.Schema({
text: String,
id: String,
createdAt: Number,
isCompleted: Boolean
});
var TODO = mongoose.model('todo', TODOschema);
module.exports = TODO;

var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
},
bacon: {
type: Number,
required: [true, 'Why no bacon?']
},
drink: {
type: String,
enum: ['Coffee', 'Tea'],
required: function() {
return this.bacon > 3;
}
}
});
¿Cómo uso esto?
var Breakfast = db.model('Breakfast', breakfastSchema);
var badBreakfast = new Breakfast({
eggs: 2,
bacon: 1,
drink: 'Milk'
});
var error = badBreakfast.validateSync();
console.log(error.errors);
// {
// eggs : 'Too few eggs',
// drink : '`Milk` is not a valid enum value for path `drink`.'
// }
Otra ejemplo más
var userSchema = new Schema({
phone: {
type: String,
validate: {
validator: function(v) {
return /\d{3}-\d{3}-\d{4}/.test(v);
},
message: '{VALUE} is not a valid phone number!'
},
required: [true, 'User phone number required']
}
});
MIDDLEWARES
MIDDLEWARES
EVERYWHERE
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
MIDDLEWARES
app.use( middleware )
app.use( (req, res, next) => {
console.log(`Hemos recibido una solicitud a ${req.url}`);
next();
})
Las funciones de middleware son funciones que tienen acceso al objeto de solicitud (req), al objeto de respuesta (res) y a la siguiente función de middleware en el ciclo de solicitud/respuestas de la aplicación. La siguiente función de middleware se denota normalmente con una variable denominada next.
IMPORTA EL ORDEN
app.use(express.json());
app.use( (req, res, next) => {
console.log(`Yo me ejecuto primero`);
req.invalidUser = true;
next();
})
app.use( (req, res, next) => {
console.log(`Y luego yo`);
if (req.invalidUser) return res.sendStatus(401)
else next()
})
app.use('/api/users', usersRouter);
IMPORTA EL ORDEN
app.use(express.json());
app.use('/api/users', usersRouter);
app.use( (req, res, next) => {
console.log(`Yo me ejecuto primero`);
req.invalidUser = true;
next();
})
app.use( (req, res, next) => {
console.log(`Y luego yo`);
if (req.invalidUser) return res.status(401).send('Invalid Request')
else next()
})
ERROR HAMIGOH
ALGUNOS MIDDLEWARES
const express = require('express');
const morgan = require('morgan');
const app = express();
app.use(morgan('combined'));
app.listen(5000);

ALGUNOS MIDDLEWARES
// Use the session middleware
app.use(session({
secret: 'keyboard cat',
cookie: { maxAge: 60000 },
resave: true,
saveUninitialized: true}))
// Access the session as req.session
app.get('/', function(req, res, next) {
if (req.session.views) {
req.session.views++;
res.setHeader('Content-Type', 'text/html');
res.send(`<p>views: ${req.session.views}</p>
<p>expires in: ${req.session.cookie.maxAge / 1000}s</p>`);
} else {
req.session.views = 1;
res.end('welcome to the session demo. refresh!');
}
})
ALGUNOS MIDDLEWARES

errorhandler + otros loggers
const app = require('express')();
const errorhandler = require('errorhandler')
const notifier = require('node-notifier');
app.use(errorhandler( { log : errorNotification } ));
app.listen(5000);
function errorNotification (err, str, req) {
var title = 'Error in ' + req.method + ' ' + req.url
notifier.notify({
title: title,
message: str
})
}

errorhandler + otros loggers
const app = require('express')();
const errorhandler = require('errorhandler')
const notifier = require('node-notifier');
if (process.env.NODE_ENV === 'development'){
app.use(errorhandler( { log : errorNotification } ));
}
app.listen(5000);
function errorNotification (err, str, req) {
var title = 'Error in ' + req.method + ' ' + req.url
notifier.notify({
title: title,
message: str
})
}

ALGUNOS MIDDLEWARES
ALGUNOS MIDDLEWARES
var compression = require('compression')
var express = require('express')
var app = express()
// compress all responses
app.use(compression())
// add all routes
ALGUNOS MIDDLEWARES

var cors = require('cors');
var app = require('express')();
app.use(cors());
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
var app = require('express')();
var cors = require('cors')
var corsOptions = {
origin: ['http://example.com' , 'http://example2.com' ]
}
app.use(cors(corsOptions));
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
AWESOME !!!
SPEGC Agosto 2022 Full Stack. ExpressJS Router & MongoDB Día 3
By Yunior González Santana
SPEGC Agosto 2022 Full Stack. ExpressJS Router & MongoDB Día 3
Nuestra API empieza a coger color ! API ordenada con RouterJS y Model conectado con MongoDB
- 200