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”.
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
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
const express = require('express');
const app = express();
// Applying middlewares and routes
app.use(express.json());
// Resources routers
const usersRouter = require('./api/users');
app.use('/api/users', usersRouter);
app.listen(5000);
server.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
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
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 !!!
¡A trabajar otra vez!
El producto evoluciona
Oye, que me han dicho que ahora sabes usar middlewares, pues mira, estaría interesante que :
- Cuando se produzca un error en nuestra api le llegue un correo al desarrollador con el error.
- También estaría chulo que si un usuario nos hace más de 20 peticiones POST en una misma sessión no le permitas hacer más peticiones post y nos informes por correo también.
- Hemos visto que hay muchas herramientas para monitorizar logs por ahí :S Investiga e implementa alguna para controlar todo lo que pasa en nuestro server de express https://www.slant.co/options/955/alternatives/~loggly-alternatives
El producto evoluciona
¿Y si mejoras el proyecto del TODOLIST?
Para una primera versión, porque no almacenas la lista de todo pero distinta para cada usuario? por ejemplo usando el módulo de express-session e identificando a las sesiones de alguna manera única.
Pero ojo, no queremos que cuando el servidor se reinicie se haya perdido todo.
Y si ... haces que cada mañana a las 9 de la mañana se envíe un correo al usuario que le diga el título de las tareas que aún no ha completado ? Haz que el usuario te indique su id mediante un post a /users
EXPRESSJS ROUTER Y COMMONJS
By Yunior González Santana
EXPRESSJS ROUTER Y COMMONJS
Tercer día con node. Limpiando EXPRESSJS
- 179