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.

 

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