{
    "componentChunkName": "component---node-modules-gatsby-theme-try-ghost-src-templates-post-js",
    "path": "/dont-stop-the-party-node-js-ix-rutas/",
    "result": {"data":{"ghostPost":{"id":"Ghost__Post__5a338158333e0f134c248f35","title":"Don't stop the party: Node JS(IX) Rutas o Middlewares","slug":"dont-stop-the-party-node-js-ix-rutas","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-5.jpg","excerpt":"Vamos a profundizar un poco en esto de las rutas, que es una de las partes\ncentrales de express(y yo diría de Node casi).\nLas rutas es lo que hemos llamado anteriormente métodos (el get que configuramos\npara probar), y como ya comentamos y vimos en la documentación oficial de\nexpress, tenemos lo siguiente\n\napp.method(urlPath,handler)\n\n\nSiendo:\n\n * app: Ya vimos que es una instancia de express.Esta parte puede ser tambien \n   router, ya veremos porque.\n * method: * GET: Se usa para pedir datos, y","custom_excerpt":null,"visibility":"public","created_at_pretty":"18 Sep 2017","published_at_pretty":"3 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-18T21:22:11.000+02:00","published_at":"2017-10-03T09:45:00.000+02:00","updated_at":"2018-01-22T09:40:30.000+01:00","meta_title":null,"meta_description":"Veamos que es eso de Middlewares o Rutas en NodeJS, que es lo básico para poder hacer nuestras propias APIs","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Vamos a profundizar un poco en esto de las rutas, que es una de las partes\ncentrales de express(y yo diría de Node casi).\nLas rutas es lo que hemos llamado anteriormente métodos (el get que configuramos\npara probar), y como ya comentamos y vimos en la documentación oficial de\nexpress, tenemos lo siguiente\n\napp.method(urlPath,handler)\n\n\nSiendo:\n\n * app: Ya vimos que es una instancia de express.Esta parte puede ser tambien \n   router, ya veremos porque.\n * method: * GET: Se usa para pedir datos, y siempre que se le llame tiene que devolver\n      lo mismo(siempre que la petición se haga de la misma forma)\n    * POST: Para crear algo, un objeto de nuestra app\n    * PUT: Se usa para actualizar datos u objetos existentes.\n    * DELETE: Elimina datos u objetos existentes y al igual que el get siempre\n      tiene que darnos el mismo resultado.\n    * ALL: Con all, express aceptaría cualquiera de los anteriores, siempre y\n      cuando el path coincida. Un posible uso sería para verificar credenciales\n      si por ejemplo un token de sesión ha caducado y el usuario puede estar\n      haciendo cualquier cosa, es decir, usando cualquiera de los otros métodos.\n   \n   \n * urlPath: Será el path que si coincide con la petición que ha recibido Node\n   ejecutará su handler asociado\n * handler: Es el callback o función que se ejecuta si coincide el path.\n\nUn detalle importante es que se comprueban las coincidencias de rutas en el\norden que están escritas por lo que puede ser una buena opción si por ejemplo\nqueremos comprobar si un usuario tiene permiso para acceder a cierta ruta o\npath.\n\nOtro tipo de ruta o middleware es la de ficheros estáticos como pueden ser\nimágenes,css o ficheros javascript, ya comenté un poco en el post anterior como\nera ya que por defecto la carpeta public estaba configurada como tal, veamoslo\nun poco en detalle\n\napp.use(express.static(path.join(__dirname, 'public')));\n\n\nCon esto lo que le estamos indicando a express y a node con este middleware es\nque todo lo que este en la carpeta public será servido como estático, ojo\nteniendo que usar la estructura de carpetas existentes, me refiero a que si\ndebajo de public tenemos una carpeta images el path deberia ser \nurlRaiz/images/imagen.jpg. Vamos a comprobarlo con el fichero css que nos crea\npor defecto express generator, que en este caso esta dentro de la carpeta \nstylesheets y tiene el nombre style.css, entonces como hemos comentado la ruta\nsería (con nuestro proyecto iniciado claro está)\n\nhttp://localhost:3000/stylesheets/style.css\n\n\nLo que nos devolvería el fichero css en el navegador\n\n\nTambién podemos indicarle a express que nos sirva los estáticos a través de un\npath o ruta virtual que nosotros le indiquemos, en lugar desde la ruta raiz. Si\nponemos esta línea en el fichero app.js de nuestro proyecto (cambiandola por la\nque nos servía estáticos antes)\n\napp.use('/ninja_static',express.static(path.join(__dirname, 'public')));\n\n\nentonces nuestra url cambiaría a\n\nhttp://localhost:3000/ninja_static/stylesheets/style.css\n\n\nEsto es muy útil si por ejemplo tenemos una estructura de carpetas de estáticos\nmuy larga y queremos realemente acortar las url, podríamos por ejemplo cambiarlo\npor\n\napp.use('/ninjacss',express.static(path.join(__dirname, 'public/stylesheets')));\n\n\nLo que nos convierte la url a\n\nhttp://localhost:3000/ninjacss/style.css\n\n\nComo véis podemos gestionar nuestras rutas como queramos para que sea más cómodo\ntrabajar con ellas.\n\nRutas/Middlewares con parámetros\nHasta ahora habíamos visto siempre como trabajar con rutas digamos estáticas \npero claro ninguna API es nunca tan simple, generalmente en la URL pasamos\ninformación para recibir un elemento específico, imaginemos por ejemplo que\nestamos creando una API que nos devuelva información sobre todos los\nsuperhéroes/villanos de los comics del mundo, ¿cuántos podrían ser? Miles como\nmínimo, lo que supondría tener que hacer una API con miles de middlewares \n¿no?...por suerte no es necesario ya que sería algo inviable, ningún servicio\naguantaría eso, lo que hacemos es que nuestro middleware reciba parámetros por\nejemplo en la url, con este estilo\n\nhttp://heroapi.com/hero/57\n\n\no este por ejemplo\n\nhttp://heroapi.com/hero?name=batman\n\n\nTenemos varias formas de hacerlo, para finalmente buscar la información usando\nese parámetro, todo en el mismo middleware.\nEn general tenemos cuatro formas de hacerlo:\n\n * En la propia ruta: /hero/57\n * Usando query string: /hero?name=batman, se conoce query string a lo que está\n   destrás de ? y son elementos de variable=valor\n * Puede ir en el cuerpo(body) de la petición, esto generalmente se usa para\n   peticiones de tipo POST o PUT, ya que al almacenar/actualizar solemos enviar\n   muchos datos y pasarlo por query string puede ser casi imposible.\n * Otra opción puede ser la cabecera, aunque esta opción exista simplemente\n   porque podemos acceder a la cabecera desde el middleware, pero no se usa para\n   datos triviales (como buscar un héroe), si no para datos como token de\n   autenticación, formatos y cosas así.\n\nEn la ruta\nEmpecemos con un ejemplo con usando la ruta, nos vamos a nuestro proyecto de\nejemplo ninja_project y vamos a modificar la ruta del index.js poniéndole un\nparámetro para cambiar el título. Quedaría así:\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/:title', function(req, res, next) {\n  var newTitle = req.params.title\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n\n\nComo véis a la ruta le hemos puesto :title y luego simplemente hemos sacado esa\ninformación de los parámetros (params) de la petición (request).\nSi ejecutamos con npm start y probamos por ejemplo con\n\nhttp://localhost:3000/Ninja\n\n\nTendríamos este resultado\n\nUsando las rutas como paso de parámetros tenemos varias opciones, para por\nejemplo si queremos que el parámetro sea opcional(si probáis sin poner /Ninja os\ndaria un error el ejemplo anterior) ponemos la ruta de esta manera\n\nrouter.get('/:title?', function(req, res, next) {\n\n\nTambién es posible usar expresiones regulares para que por ejemplo solo admita\nnúmeros\n\nrouter.get('/:id([0-9]+)', function(req, res, next) {\n\n\nY es posible poner varios\n\nrouter.get('/:type(villain|hero)/data/:name)', function(req, res, next) {\n\n\nEsta aceptaría en type solo villain o hero y en name cualquier cosa.\nLas rutas son bastante dinámicas para poder gestionar middlewares de manera más\ncómoda y segura para nosotros(evitando datos de algún tipo que no queremos\nrecibir).\n\nUsando query string\nAhora veamos un ejemplo con la segunda forma, que veréis que es muy parecido.\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  console.log(req.query);\n  var newTitle = req.query.title;\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n\n\nHemos vuelto a dejar la ruta o path como estaba y en lugar de obtener el dato de\ntitle de los parámetros de la url, lo hacemos con la query y ¿como usamos esto?\nHe puesto también un console.log para que veáis como recibimos los elementos de\ntipo query string. Simplemente poner\n\nhttp://localhost:3000/?title=Ninja\n\n\nAl probar obtendríamos el mismo resultado, y si miráis el log de la consola\nveréis como recibe los parámetros de la query, como un objeto clave= valor\n\n\n\nMétodos de respuesta\nHasta ahora hemos estado centrados todo el rato en ala captura de la petición,\nes decir, en la parte request pero ¿que pasa con la respuesta? Vamos a ver\nalgunos de los métodos de respuesta más usados, pero lo mejor es que miréis la \ndocumentación [http://expressjs.com/es/4x/api.html#res] que vienen todos y muy\nbien explicados:\n\n * res.send: Lo hemos usado ya en algún ejemplo, responde como puede a lo que le\n   pongas jejeje, funciona bien con buffer, strings, objetos, arrays(estos dos\n   últimos los devolveria como un JSON)...\n\nres.send('Hola Ninjas')\n\n\n * res.render: También lo hemos usado, nos devuelve una página renderizada\n   usando algún template y si acaso usando los parámetros que le pasemos\n\nres.render('index',{title: 'Super Título Ninja'});\n\n\n * res.json: Respuesta específica como JSON\n\nres.json({ name: 'Batman'});\n\n\n * res.download: Devuelve directamente un fichero, este sería el caso típico en\n   el que nos aparece la ventana de guardar en el navegador\n\nres.download('/rutaYNombreFichero.doc','nombreOpcionalDelFichero');\n\n\n * res.redirect: Redireccionando al usuario a otro sitio con un código de estado\n   302 por defecto(esto se puede cambiar, más abajo lo veremos). En este caso\n   tenemos varias opciones para la redirección. * Ruta relativa al root del\n      usuario:\n   \n   res.redirect('/root/path/algo');\n   \n   \n    * Url absoluta:\n   \n   res.redirect('http://urlnueva');\n   \n   \n    * Pasandole también el código de estado:\n   \n   res.redirect(301,'http://urlnueva');\n   \n   \n    * Ruta según el path actual:\n   \n   res.redirect('../ruta/algo')\n   \n   \n    * También podemos hacer que vuelva a la página anterior:\n   \n   res.redirect('back')\n   \n   \n   \n\nSi miráis la documentación hay muchos más y todos estos pueden admitir más\nparámetros, con más opciones de configuración. Comentar que casi todas las\nopciones de respuesta soportan cambiar el código de estado, solo tenemos que\nencadenar métodos\n\nres.status(500).send('Error');\nres.status(200).render('index');\n\n\nMuy cómodo si queremos devolver algún código específico que no sea el de por\ndefecto de cada respuesta.\nPoco a poco veremos como van saliendo distintos tipos de respuesta en los\nejemplos que vayamos haciendo.\n\nCreando nuestra propia ruta\nHasta ahora hemos estado trabajando con lo que ya nos había configurado express,\npero ¿y si queremos crear nuestra propia ruta?¿Cuáles serían los pasos? Bien,\npues vamos a verlos.\nLo primero de todo es crearnos un fichero nuevo en la carpeta routes(para\nmantener el orden), por ejemplo lo voy a llamar ninjas.js y de momento le\nponemos esto\n\n'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/heros', function(req, res, next) {\n  res.json({ninjas: \"Somos un montón de ninjas\"})\n});\n\nmodule.exports = router;\n\n\nSi os fijáis lo que hacemos es instanciar un Router, que es una de las formas de\ncrear rutas para pasarselas a express. A este router le hemos indicado el método\na usar, su path y su respuesta y por último lo hemos exportado como si de un\nmódulo se tratara para así poder usarlo en cualquier parte de nuestra\naplicación.\nLo siguientes es irnos al app.js que, como ya comentamos en su momento, entre\notras cosas tiene la instanciación de las rutas, y preparamos la nuestra, para\nello lo primero es requerirla, y lo hacemos debajo de las otras\n\nvar index = require('./routes/index');\nvar users = require('./routes/users');\nvar ninjas = require('./routes/ninjas');\n\n\nYa la tenemos disponible en nuestro app.js pero realmente todavia no le hemos\nindicado donde tiene que escuchar y que tiene que hacer, para hacerlo buscamos\ndonde ha creado las otras y hacemos lo propio\n\napp.use('/', index);\napp.use('/users', users);\napp.use('/ninjas',ninjas);\n\n\nY listo con esto ya tendríamos nuestra propia ruta, como véis es bastante\nsencillo. Ahora vamos a probarla peeeeero ojo al dato, tenemos que tener en\ncuenta:\n\n * La ruta o path que hemos puesto en el app.use\n * La ruta o path que hemos puesto en ninjas.js\n\nEsto lo remarco porque realmente esto lo que esta haciendo es escuchar lo\nprimero en el path /ninjas y según ese path lo que hace es indicarle al \nninjas.js que es su turno (en plan enga majete a currar), pero claro este router \ntiene configurado también su propio path, es decir que a partir del path por el\nque ha sido convocado en el app.use tiene que cumplir el segundo que en este\ncaso seria heros, por lo que la ruta quedariía así\n\nhttp://localhost:3000/ninjas/heros\n\n\nY esto nos devolvería un json\n\nUna vez que entiendes como funciona, ves que realmente es bastante sencillo\nconfigurar y trabajar con las rutas de express.\n\nDurante todo el post, ha estado apareciendo la palabra middleware pero , ¿que es\nexáctamente un middleware? Un middleware es un handler o manejador que responde\na un tipo de petición o a todas. Básicamente es lo que hemos estado haciendo\ntodo el rato. Veamos algunos detalles de su implementación.\nSi os habéis fijado en nuestros middlewares que nos ha creado express, en los\nparámetros que recibe la función handler, tenemos esto\n\nfunction(req, res, next) {\n\n\nHemos visto que es req y res pero ¿que es next?, básicamente next es un método\npara indicar que continue hasta el siguiente middleware si no queremos terminar\nla ejecución. Supongamos por ejemplo que queremos comprobar el token de acceso\nde un usuario o sin ir más lejos si un usuario existe antes de tener acceso a\nningún otro middleware. En este caso podríamos crear un middleware que en todas\nlas peticiones compruebe cualquiera de los dos casos y a continuación una vez\ncomprobado simplemente le diríamos que continuará al siguiente middleware para\ndarle acceso a lo que realmente ha solicitado, es decir, acceso al middleware\nque nos ha mandado como request.\nAhora vamos a ver un ejemplo muy sencillito para que se entienda mejor, pero\nantes comentar que si un middleware no responde de ninguna forma y no indica\nexplicitamente que vaya al siguiente middleware no saldrá del handler en\ncuestión y nos dará timeout la petición. Vamos con el ejemplo, primero\ncomprobemos que nos da timeout, para elloen nuestro app.js antes de indicar los\nmiddlewares ponemos los siguiente\n\napp.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n});\n//Encima de este\napp.use('/', index);\n\n\nY comprobamos lo que pasa al acceder\n\nEl log muestra nuestro nuevo middleware pero la ventana se queda a la espera de\nrecibir algo\n\nAhora pongamos el next a ver que pasa\n\napp.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n  next();\n});\n\n\nComo véis en la consola ha pasado por el middleware(2 veces) y ha continuado\nhasta el siguiente middleware que coincide que es el index\n\nY como no hemos pasado en la queryString(que es como lo dejamos antes) solo nos\naparece el welcome\n\nPero por lo menos vemos que ha continuado sin problemas.\nImportante no podemos responder a un middleware y pasar al siguiente, lo que sea\nque queramos hacer tiene que ser al revés, es decir, no podemos responder 2\nveces a la misma petición ya que el cliente no espera más de una respuesta, si\nen algún momento recibís en consola un log que ponga algo similar a header ya\nenvíado o similar es porque estáis intentando responder dos veces.\nLos middlewares podemos separarlos en varios tipos (como concepto de uso):\n\n * Tenemos los middlewares a nivel de aplicación, es decir, los que ejecutamos\n   en toda actividad de la app, y son los que normalmente deberían estar en el \n   app.js. Acabamos de usar uno\n\napp.use('/', index);\n\n\n * Middleware a nivel de router: los que ponemos en la carpeta routes y\n   responden a un tipo de petición o path específicos\n\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {}\n\n\n * Middleware de error: Estos los ponemos los últimos y como su nombre indica\n   responderan cuando tengamos un error. Si miramos nuestro app.js vemos que\n   tenemos uno al final. Se diferencian en que reciben un parámetro más err.\n\n// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n\n\nNormalmente son llamados por nosotros pasándoselo al next, si os fijáis en el \napp.js, justo encima del middleware de error tenemos uno que captura todas las\npeticiones que no han coincidido y le pasa un mensaje de tipo 404 al middleware\nde error con next(err)(básicamente en cuanto a next le pasemos algo irá al\nhandler de error)\n\n// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n\n\n * Tenemos más middlewares oficiales, que básicamente son los mantenidos en el\n   módulo connect que usa express. Podéis encontrar informacíon aquí\n   [https://github.com/senchalabs/connect].\n * Por último tenemos otros que llamaríamos middlewares de terceros, que son los\n   creados y mantenidos por la comunidad, muchos de ellos aparecen en esta\n   página de express [http://expressjs.com/en/resources/middleware.html]\n\nCreo que más o menos he comentado casi todo lo importante referente a los\nmiddlewares (ha sido un post más largo de lo habitual jejejejje), espero que a\npartir de ahora podáis hacer los vuestros sin problemas, en el siguiente post\nveremos un poco los templates y alguna cosa más. Sin mucho más nos veeemossss un\nabrazoooorrr","html":"<!--kg-card-begin: markdown--><p>Vamos a profundizar un poco en esto de las rutas, que es una de las partes centrales de express(y yo diría de Node casi).<br>\nLas rutas es lo que hemos llamado anteriormente métodos (el <strong>get</strong> que configuramos para probar), y como ya comentamos y vimos en la documentación oficial de express, tenemos lo siguiente</p>\n<pre><code>app.method(urlPath,handler)\n</code></pre>\n<p>Siendo:</p>\n<ul>\n<li><strong>app:</strong> Ya vimos que es una instancia de express.Esta parte puede ser tambien <strong>router</strong>, ya veremos porque.</li>\n<li><strong>method:</strong>\n<ul>\n<li><strong>GET:</strong> Se usa para pedir datos, y siempre que se le llame tiene que devolver lo mismo(siempre que la petición se haga de la misma forma)</li>\n<li><strong>POST:</strong> Para crear algo, un objeto de nuestra app</li>\n<li><strong>PUT:</strong> Se usa para actualizar datos u objetos existentes.</li>\n<li><strong>DELETE:</strong> Elimina datos u objetos existentes y al igual que el get siempre tiene que darnos el mismo resultado.</li>\n<li><strong>ALL:</strong> Con all, express aceptaría cualquiera de los anteriores, siempre y cuando el path coincida. Un posible uso sería para verificar credenciales si por ejemplo un token de sesión ha caducado y el usuario puede estar haciendo cualquier cosa, es decir, usando cualquiera de los otros métodos.</li>\n</ul>\n</li>\n<li><strong>urlPath:</strong> Será el path que si coincide con la petición que ha recibido Node ejecutará su <strong>handler</strong> asociado</li>\n<li><strong>handler:</strong> Es el callback o función que se ejecuta si coincide el path.</li>\n</ul>\n<p>Un detalle <strong>importante</strong> es que se comprueban las coincidencias de rutas en el orden que están escritas por lo que puede ser una buena opción si por ejemplo queremos comprobar si un usuario tiene permiso para acceder a cierta ruta o path.</p>\n<p>Otro tipo de ruta o middleware es la de <strong>ficheros estáticos</strong> como pueden ser imágenes,css o ficheros javascript, ya comenté un poco en el post anterior como era ya que por defecto la carpeta <strong>public</strong> estaba configurada como tal, veamoslo un poco en detalle</p>\n<pre><code>app.use(express.static(path.join(__dirname, 'public')));\n</code></pre>\n<p>Con esto lo que le estamos indicando a express y a node con este middleware es que todo lo que este en la carpeta <strong>public</strong> será servido como estático, ojo teniendo que usar la estructura de carpetas existentes, me refiero a que si debajo de public tenemos una carpeta <em>images</em> el path deberia ser <strong>urlRaiz/images/imagen.jpg</strong>. Vamos a comprobarlo con el fichero <strong>css</strong> que nos crea por defecto <em>express generator</em>, que en este caso esta dentro de la carpeta <em>stylesheets</em> y tiene el nombre <em>style.css</em>, entonces como hemos comentado la ruta sería (con nuestro proyecto iniciado claro está)</p>\n<pre><code>http://localhost:3000/stylesheets/style.css\n</code></pre>\n<p>Lo que nos devolvería el fichero css en el navegador<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-19-at-08.51.39.png\" alt=\"Css static example\"></p>\n<p>También podemos indicarle a express que nos sirva los estáticos a través de un path o ruta virtual que nosotros le indiquemos, en lugar desde la ruta raiz. Si ponemos esta línea en el fichero <strong>app.js</strong> de nuestro proyecto (cambiandola por la que nos servía estáticos antes)</p>\n<pre><code>app.use('/ninja_static',express.static(path.join(__dirname, 'public')));\n</code></pre>\n<p>entonces nuestra url cambiaría a</p>\n<pre><code>http://localhost:3000/ninja_static/stylesheets/style.css\n</code></pre>\n<p>Esto es muy útil si por ejemplo tenemos una estructura de carpetas de estáticos muy larga y queremos realemente acortar las url, podríamos por ejemplo cambiarlo por</p>\n<pre><code>app.use('/ninjacss',express.static(path.join(__dirname, 'public/stylesheets')));\n</code></pre>\n<p>Lo que nos convierte la url a</p>\n<pre><code>http://localhost:3000/ninjacss/style.css\n</code></pre>\n<p>Como véis podemos gestionar nuestras rutas como queramos para que sea más cómodo trabajar con ellas.</p>\n<h3 id=\"rutasmiddlewaresconparmetros\">Rutas/Middlewares con parámetros</h3>\n<p>Hasta ahora habíamos visto siempre como trabajar con rutas digamos <em>estáticas</em> pero claro ninguna API es nunca tan simple, generalmente en la URL pasamos información para recibir un elemento específico, imaginemos por ejemplo que estamos creando una API que nos devuelva información sobre todos los superhéroes/villanos de los comics del mundo, ¿cuántos podrían ser? Miles como mínimo, lo que supondría tener que hacer una API con miles de <strong>middlewares</strong> ¿no?...por suerte no es necesario ya que sería algo inviable, ningún servicio aguantaría eso, lo que hacemos es que nuestro <em>middleware</em> reciba parámetros por ejemplo en la url, con este estilo</p>\n<pre><code>http://heroapi.com/hero/57\n</code></pre>\n<p>o este por ejemplo</p>\n<pre><code>http://heroapi.com/hero?name=batman\n</code></pre>\n<p>Tenemos varias formas de hacerlo, para finalmente buscar la información usando ese parámetro, todo en el mismo <em>middleware</em>.<br>\nEn general tenemos cuatro formas de hacerlo:</p>\n<ul>\n<li>En la propia ruta: /hero/57</li>\n<li>Usando <em>query string</em>: /hero?name=batman, se conoce <em>query string</em> a lo que está destrás de <strong>?</strong> y son elementos de <em>variable=valor</em></li>\n<li>Puede ir en el cuerpo(body) de la petición, esto generalmente se usa para peticiones de tipo POST o PUT, ya que al almacenar/actualizar solemos enviar muchos datos y pasarlo por <em>query string</em> puede ser casi imposible.</li>\n<li>Otra opción puede ser la cabecera, aunque esta opción exista simplemente porque podemos acceder a la cabecera desde el middleware, pero no se usa para datos triviales (como buscar un héroe), si no para datos como token de autenticación, formatos y cosas así.</li>\n</ul>\n<h4 id=\"enlaruta\">En la ruta</h4>\n<p>Empecemos con un ejemplo con usando la ruta, nos vamos a nuestro proyecto de ejemplo <strong>ninja_project</strong> y vamos a modificar la ruta del <strong>index.js</strong> poniéndole un parámetro para cambiar el título. Quedaría así:</p>\n<pre><code>var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/:title', function(req, res, next) {\n  var newTitle = req.params.title\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Como véis a la ruta le hemos puesto <strong>:title</strong> y luego simplemente hemos sacado esa información de los parámetros (params) de la petición (request).<br>\nSi ejecutamos con <strong>npm start</strong> y probamos por ejemplo con</p>\n<pre><code>http://localhost:3000/Ninja\n</code></pre>\n<p>Tendríamos este resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.21.56.png\" alt=\"Middleware route params example\"><br>\nUsando las rutas como paso de parámetros tenemos varias opciones, para por ejemplo si queremos que el parámetro sea opcional(si probáis sin poner /Ninja os daria un error el ejemplo anterior) ponemos la ruta de esta manera</p>\n<pre><code>router.get('/:title?', function(req, res, next) {\n</code></pre>\n<p>También es posible usar expresiones regulares para que por ejemplo solo admita números</p>\n<pre><code>router.get('/:id([0-9]+)', function(req, res, next) {\n</code></pre>\n<p>Y es posible poner varios</p>\n<pre><code>router.get('/:type(villain|hero)/data/:name)', function(req, res, next) {\n</code></pre>\n<p>Esta aceptaría en type solo <em>villain o hero</em> y en name cualquier cosa.<br>\nLas rutas son bastante dinámicas para poder gestionar <em>middlewares</em> de manera más cómoda y segura para nosotros(evitando datos de algún tipo que no queremos recibir).</p>\n<h4 id=\"usandoquerystring\">Usando query string</h4>\n<p>Ahora veamos un ejemplo con la segunda forma, que veréis que es muy parecido.</p>\n<pre><code>var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  console.log(req.query);\n  var newTitle = req.query.title;\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Hemos vuelto a dejar la ruta o path como estaba y en lugar de obtener el dato de title de los parámetros de la url, lo hacemos con la query y ¿como usamos esto? He puesto también un console.log para que veáis como recibimos los elementos de tipo query string. Simplemente poner</p>\n<pre><code>http://localhost:3000/?title=Ninja\n</code></pre>\n<p>Al probar obtendríamos el mismo resultado, y si miráis el log de la consola veréis como recibe los parámetros de la query, como un objeto clave= valor<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.30.05.png\" alt=\"Middleware query string example\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.29.57.png\" alt=\"Log query string example\"></p>\n<h4 id=\"mtodosderespuesta\">Métodos de respuesta</h4>\n<p>Hasta ahora hemos estado centrados todo el rato en ala captura de la petición, es decir, en la parte <strong>request</strong> pero ¿que pasa con la respuesta? Vamos a ver algunos de los métodos de respuesta más usados, pero lo mejor es que miréis la <a href=\"http://expressjs.com/es/4x/api.html#res\">documentación</a> que vienen todos y muy bien explicados:</p>\n<ul>\n<li><strong>res.send</strong>: Lo hemos usado ya en algún ejemplo, responde como puede a lo que le pongas jejeje, funciona bien con buffer, strings, objetos, arrays(estos dos últimos los devolveria como un JSON)...</li>\n</ul>\n<pre><code>res.send('Hola Ninjas')\n</code></pre>\n<ul>\n<li><strong>res.render</strong>: También lo hemos usado, nos devuelve una página renderizada usando algún template y si acaso usando los parámetros que le pasemos</li>\n</ul>\n<pre><code>res.render('index',{title: 'Super Título Ninja'});\n</code></pre>\n<ul>\n<li><strong>res.json</strong>: Respuesta específica como JSON</li>\n</ul>\n<pre><code>res.json({ name: 'Batman'});\n</code></pre>\n<ul>\n<li><strong>res.download</strong>: Devuelve directamente un fichero, este sería el caso típico en el que nos aparece la ventana de <em>guardar</em> en el navegador</li>\n</ul>\n<pre><code>res.download('/rutaYNombreFichero.doc','nombreOpcionalDelFichero');\n</code></pre>\n<ul>\n<li><strong>res.redirect</strong>: Redireccionando al usuario a otro sitio con un código de estado 302 por defecto(esto se puede cambiar, más abajo lo veremos). En este caso tenemos varias opciones para la redirección.\n<ul>\n<li>Ruta relativa al root del usuario:</li>\n</ul>\n<pre><code>res.redirect('/root/path/algo');\n</code></pre>\n<ul>\n<li>Url absoluta:</li>\n</ul>\n<pre><code>res.redirect('http://urlnueva');\n</code></pre>\n<ul>\n<li>Pasandole también el código de estado:</li>\n</ul>\n<pre><code>res.redirect(301,'http://urlnueva');\n</code></pre>\n<ul>\n<li>Ruta según el path actual:</li>\n</ul>\n<pre><code>res.redirect('../ruta/algo')\n</code></pre>\n<ul>\n<li>También podemos hacer que vuelva a la página anterior:</li>\n</ul>\n<pre><code>res.redirect('back')\n</code></pre>\n</li>\n</ul>\n<p>Si miráis la documentación hay muchos más y todos estos pueden admitir más parámetros, con más opciones de configuración. Comentar que casi todas las opciones de respuesta soportan cambiar el código de estado, solo tenemos que encadenar métodos</p>\n<pre><code>res.status(500).send('Error');\nres.status(200).render('index');\n</code></pre>\n<p>Muy cómodo si queremos devolver algún código específico que no sea el de por defecto de cada respuesta.<br>\nPoco a poco veremos como van saliendo distintos tipos de respuesta en los ejemplos que vayamos haciendo.</p>\n<h3 id=\"creandonuestrapropiaruta\">Creando nuestra propia ruta</h3>\n<p>Hasta ahora hemos estado trabajando con lo que ya nos había configurado <strong>express</strong>, pero ¿y si queremos crear nuestra propia ruta?¿Cuáles serían los pasos? Bien, pues vamos a verlos.<br>\nLo primero de todo es crearnos un fichero nuevo en la carpeta <em>routes</em>(para mantener el orden), por ejemplo lo voy a llamar <strong>ninjas.js</strong> y de momento le ponemos esto</p>\n<pre><code>'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/heros', function(req, res, next) {\n  res.json({ninjas: &quot;Somos un montón de ninjas&quot;})\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Si os fijáis lo que hacemos es instanciar un <strong>Router</strong>, que es una de las formas de crear rutas para pasarselas a express. A este <em>router</em> le hemos indicado el método a usar, su path y su respuesta y por último lo hemos exportado como si de un módulo se tratara para así poder usarlo en cualquier parte de nuestra aplicación.<br>\nLo siguientes es irnos al <strong>app.js</strong> que, como ya comentamos en su momento, entre otras cosas tiene la instanciación de las rutas, y preparamos la nuestra, para ello lo primero es <em>requerirla</em>, y lo hacemos debajo de las otras</p>\n<pre><code>var index = require('./routes/index');\nvar users = require('./routes/users');\nvar ninjas = require('./routes/ninjas');\n</code></pre>\n<p>Ya la tenemos disponible en nuestro <em>app.js</em> pero realmente todavia no le hemos indicado donde tiene que escuchar y que tiene que hacer, para hacerlo buscamos donde ha creado las otras y hacemos lo propio</p>\n<pre><code>app.use('/', index);\napp.use('/users', users);\napp.use('/ninjas',ninjas);\n</code></pre>\n<p>Y listo con esto ya tendríamos nuestra propia ruta, como véis es bastante sencillo. Ahora vamos a probarla peeeeero ojo al dato, tenemos que tener en cuenta:</p>\n<ul>\n<li>La ruta o path que hemos puesto en el <strong>app.use</strong></li>\n<li>La ruta o path que hemos puesto en <strong>ninjas.js</strong></li>\n</ul>\n<p>Esto lo remarco porque realmente esto lo que esta haciendo es escuchar lo primero en el path <strong>/ninjas</strong> y según ese path lo que hace es indicarle al <strong>ninjas.js</strong> que es su turno (en plan enga majete a currar), pero claro este <em>router</em> tiene configurado también su propio path, es decir que a partir del path por el que ha sido convocado en el <em>app.use</em> tiene que cumplir el segundo que en este caso seria <strong>heros</strong>, por lo que la ruta quedariía así</p>\n<pre><code>http://localhost:3000/ninjas/heros\n</code></pre>\n<p>Y esto nos devolvería un json<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-21-at-09.28.26.png\" alt=\"Own router example\"><br>\nUna vez que entiendes como funciona, ves que realmente es bastante sencillo configurar y trabajar con las rutas de express.</p>\n<p>Durante todo el post, ha estado apareciendo la palabra <strong>middleware</strong> pero , ¿que es exáctamente un middleware? Un <strong>middleware</strong> es un handler o manejador que responde a un tipo de petición o a todas. Básicamente es lo que hemos estado haciendo todo el rato. Veamos algunos detalles de su implementación.<br>\nSi os habéis fijado en nuestros middlewares que nos ha creado express, en los parámetros que recibe la función handler, tenemos esto</p>\n<pre><code>function(req, res, next) {\n</code></pre>\n<p>Hemos visto que es <strong>req y res</strong> pero ¿que es next?, básicamente <strong>next</strong> es un método para indicar que continue hasta el siguiente middleware si no queremos terminar la ejecución. Supongamos por ejemplo que queremos comprobar el token de acceso de un usuario o sin ir más lejos si un usuario existe antes de tener acceso a ningún otro middleware. En este caso podríamos crear un middleware que en todas las peticiones compruebe cualquiera de los dos casos y a continuación una vez comprobado simplemente le diríamos que continuará al siguiente middleware para darle acceso a lo que realmente ha solicitado, es decir, acceso al middleware que nos ha mandado como <strong>request</strong>.<br>\nAhora vamos a ver un ejemplo muy sencillito para que se entienda mejor, pero antes comentar que si un middleware <strong>no responde de ninguna forma y no indica explicitamente que vaya al siguiente middleware no saldrá del handler en cuestión y nos dará timeout la petición</strong>. Vamos con el ejemplo, primero comprobemos que nos da timeout, para elloen nuestro <strong>app.js</strong> antes de indicar los middlewares ponemos los siguiente</p>\n<pre><code>app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n});\n//Encima de este\napp.use('/', index);\n</code></pre>\n<p>Y comprobamos lo que pasa al acceder<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.11.37.png\" alt=\"Middleware timeout\"><br>\nEl log muestra nuestro nuevo middleware pero la ventana se queda a la espera de recibir algo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.12.01.png\" alt=\"Timeout example\"><br>\nAhora pongamos el <strong>next</strong> a ver que pasa</p>\n<pre><code>app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n  next();\n});\n</code></pre>\n<p>Como véis en la consola ha pasado por el middleware(2 veces) y ha continuado hasta el siguiente middleware que coincide que es el <strong>index</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.14.56.png\" alt=\"Screen-Shot-2017-09-22-at-09.14.56\"><br>\nY como no hemos pasado en la queryString(que es como lo dejamos antes) solo nos aparece el <strong>welcome</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.17.10.png\" alt=\"Screen-Shot-2017-09-22-at-09.17.10\"><br>\nPero por lo menos vemos que ha continuado sin problemas.<br>\nImportante <strong>no podemos responder a un middleware y pasar al siguiente, lo que sea que queramos hacer tiene que ser al revés</strong>, es decir, no podemos responder 2 veces a la misma petición ya que el cliente no espera más de una respuesta, si en algún momento recibís en consola un log que ponga algo similar a <em>header ya envíado</em> o similar es porque estáis intentando responder dos veces.<br>\nLos middlewares podemos separarlos en varios tipos (como concepto de uso):</p>\n<ul>\n<li>Tenemos los middlewares a <strong>nivel de aplicación</strong>, es decir, los que ejecutamos en toda actividad de la app, y son los que normalmente deberían estar en el <strong>app.js</strong>. Acabamos de usar uno</li>\n</ul>\n<pre><code>app.use('/', index);\n</code></pre>\n<ul>\n<li>Middleware a <strong>nivel de router</strong>: los que ponemos en la carpeta <strong>routes</strong> y responden a un tipo de petición o path específicos</li>\n</ul>\n<pre><code>var router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {}\n</code></pre>\n<ul>\n<li>Middleware <strong>de error</strong>: Estos los ponemos los últimos y como su nombre indica responderan cuando tengamos un error. Si miramos nuestro <strong>app.js</strong> vemos que tenemos uno al final. Se diferencian en que reciben un parámetro más <strong>err</strong>.</li>\n</ul>\n<pre><code>// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n</code></pre>\n<p>Normalmente son llamados por nosotros pasándoselo al next, si os fijáis en el <strong>app.js</strong>, justo encima del middleware de error tenemos uno que captura todas las peticiones que no han coincidido y le pasa un mensaje de tipo 404 al middleware de error con <strong>next(err)</strong>(básicamente en cuanto a next le pasemos algo irá al handler de error)</p>\n<pre><code>// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n</code></pre>\n<ul>\n<li>Tenemos más <strong>middlewares oficiales</strong>, que básicamente son los mantenidos en el módulo <strong>connect</strong> que usa express. Podéis encontrar informacíon <a href=\"https://github.com/senchalabs/connect\">aquí</a>.</li>\n<li>Por último tenemos otros que llamaríamos <strong>middlewares de terceros</strong>, que son los creados y mantenidos por la comunidad, muchos de ellos aparecen en <a href=\"http://expressjs.com/en/resources/middleware.html\">esta página de express</a></li>\n</ul>\n<p>Creo que más o menos he comentado casi todo lo importante referente a los middlewares (ha sido un post más largo de lo habitual jejejejje), espero que a partir de ahora podáis hacer los vuestros sin problemas, en el siguiente post veremos un poco los templates y alguna cosa más. Sin mucho más nos veeemossss un abrazoooorrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-ix-rutas/","canonical_url":null,"uuid":"b9cc95c8-2f3a-4ab3-83e3-a3e502ab0146","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59c01ce36c31a60001f69f59","reading_time":11,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Vamos a profundizar un poco en esto de las rutas, que es una de las partes centrales de express(y yo diría de Node casi).<br>\nLas rutas es lo que hemos llamado anteriormente métodos (el <strong>get</strong> que configuramos para probar), y como ya comentamos y vimos en la documentación oficial de express, tenemos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.method(urlPath,handler)\n</code></pre></div>\n<p>Siendo:</p>\n<ul>\n<li><strong>app:</strong> Ya vimos que es una instancia de express.Esta parte puede ser tambien <strong>router</strong>, ya veremos porque.</li>\n<li><strong>method:</strong>\n<ul>\n<li><strong>GET:</strong> Se usa para pedir datos, y siempre que se le llame tiene que devolver lo mismo(siempre que la petición se haga de la misma forma)</li>\n<li><strong>POST:</strong> Para crear algo, un objeto de nuestra app</li>\n<li><strong>PUT:</strong> Se usa para actualizar datos u objetos existentes.</li>\n<li><strong>DELETE:</strong> Elimina datos u objetos existentes y al igual que el get siempre tiene que darnos el mismo resultado.</li>\n<li><strong>ALL:</strong> Con all, express aceptaría cualquiera de los anteriores, siempre y cuando el path coincida. Un posible uso sería para verificar credenciales si por ejemplo un token de sesión ha caducado y el usuario puede estar haciendo cualquier cosa, es decir, usando cualquiera de los otros métodos.</li>\n</ul>\n</li>\n<li><strong>urlPath:</strong> Será el path que si coincide con la petición que ha recibido Node ejecutará su <strong>handler</strong> asociado</li>\n<li><strong>handler:</strong> Es el callback o función que se ejecuta si coincide el path.</li>\n</ul>\n<p>Un detalle <strong>importante</strong> es que se comprueban las coincidencias de rutas en el orden que están escritas por lo que puede ser una buena opción si por ejemplo queremos comprobar si un usuario tiene permiso para acceder a cierta ruta o path.</p>\n<p>Otro tipo de ruta o middleware es la de <strong>ficheros estáticos</strong> como pueden ser imágenes,css o ficheros javascript, ya comenté un poco en el post anterior como era ya que por defecto la carpeta <strong>public</strong> estaba configurada como tal, veamoslo un poco en detalle</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use(express.static(path.join(__dirname, 'public')));\n</code></pre></div>\n<p>Con esto lo que le estamos indicando a express y a node con este middleware es que todo lo que este en la carpeta <strong>public</strong> será servido como estático, ojo teniendo que usar la estructura de carpetas existentes, me refiero a que si debajo de public tenemos una carpeta <em>images</em> el path deberia ser <strong>urlRaiz/images/imagen.jpg</strong>. Vamos a comprobarlo con el fichero <strong>css</strong> que nos crea por defecto <em>express generator</em>, que en este caso esta dentro de la carpeta <em>stylesheets</em> y tiene el nombre <em>style.css</em>, entonces como hemos comentado la ruta sería (con nuestro proyecto iniciado claro está)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/stylesheets/style.css\n</code></pre></div>\n<p>Lo que nos devolvería el fichero css en el navegador<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-19-at-08.51.39.png\" alt=\"Css static example\"></p>\n<p>También podemos indicarle a express que nos sirva los estáticos a través de un path o ruta virtual que nosotros le indiquemos, en lugar desde la ruta raiz. Si ponemos esta línea en el fichero <strong>app.js</strong> de nuestro proyecto (cambiandola por la que nos servía estáticos antes)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/ninja_static',express.static(path.join(__dirname, 'public')));\n</code></pre></div>\n<p>entonces nuestra url cambiaría a</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/ninja_static/stylesheets/style.css\n</code></pre></div>\n<p>Esto es muy útil si por ejemplo tenemos una estructura de carpetas de estáticos muy larga y queremos realemente acortar las url, podríamos por ejemplo cambiarlo por</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/ninjacss',express.static(path.join(__dirname, 'public/stylesheets')));\n</code></pre></div>\n<p>Lo que nos convierte la url a</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/ninjacss/style.css\n</code></pre></div>\n<p>Como véis podemos gestionar nuestras rutas como queramos para que sea más cómodo trabajar con ellas.</p>\n<h3 id=\"rutasmiddlewaresconparmetros\">Rutas/Middlewares con parámetros</h3>\n<p>Hasta ahora habíamos visto siempre como trabajar con rutas digamos <em>estáticas</em> pero claro ninguna API es nunca tan simple, generalmente en la URL pasamos información para recibir un elemento específico, imaginemos por ejemplo que estamos creando una API que nos devuelva información sobre todos los superhéroes/villanos de los comics del mundo, ¿cuántos podrían ser? Miles como mínimo, lo que supondría tener que hacer una API con miles de <strong>middlewares</strong> ¿no?...por suerte no es necesario ya que sería algo inviable, ningún servicio aguantaría eso, lo que hacemos es que nuestro <em>middleware</em> reciba parámetros por ejemplo en la url, con este estilo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://heroapi.com/hero/57\n</code></pre></div>\n<p>o este por ejemplo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://heroapi.com/hero?name=batman\n</code></pre></div>\n<p>Tenemos varias formas de hacerlo, para finalmente buscar la información usando ese parámetro, todo en el mismo <em>middleware</em>.<br>\nEn general tenemos cuatro formas de hacerlo:</p>\n<ul>\n<li>En la propia ruta: /hero/57</li>\n<li>Usando <em>query string</em>: /hero?name=batman, se conoce <em>query string</em> a lo que está destrás de <strong>?</strong> y son elementos de <em>variable=valor</em></li>\n<li>Puede ir en el cuerpo(body) de la petición, esto generalmente se usa para peticiones de tipo POST o PUT, ya que al almacenar/actualizar solemos enviar muchos datos y pasarlo por <em>query string</em> puede ser casi imposible.</li>\n<li>Otra opción puede ser la cabecera, aunque esta opción exista simplemente porque podemos acceder a la cabecera desde el middleware, pero no se usa para datos triviales (como buscar un héroe), si no para datos como token de autenticación, formatos y cosas así.</li>\n</ul>\n<h4 id=\"enlaruta\">En la ruta</h4>\n<p>Empecemos con un ejemplo con usando la ruta, nos vamos a nuestro proyecto de ejemplo <strong>ninja_project</strong> y vamos a modificar la ruta del <strong>index.js</strong> poniéndole un parámetro para cambiar el título. Quedaría así:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/:title', function(req, res, next) {\n  var newTitle = req.params.title\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Como véis a la ruta le hemos puesto <strong>:title</strong> y luego simplemente hemos sacado esa información de los parámetros (params) de la petición (request).<br>\nSi ejecutamos con <strong>npm start</strong> y probamos por ejemplo con</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/Ninja\n</code></pre></div>\n<p>Tendríamos este resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.21.56.png\" alt=\"Middleware route params example\"><br>\nUsando las rutas como paso de parámetros tenemos varias opciones, para por ejemplo si queremos que el parámetro sea opcional(si probáis sin poner /Ninja os daria un error el ejemplo anterior) ponemos la ruta de esta manera</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/:title?', function(req, res, next) {\n</code></pre></div>\n<p>También es posible usar expresiones regulares para que por ejemplo solo admita números</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/:id([0-9]+)', function(req, res, next) {\n</code></pre></div>\n<p>Y es posible poner varios</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/:type(villain|hero)/data/:name)', function(req, res, next) {\n</code></pre></div>\n<p>Esta aceptaría en type solo <em>villain o hero</em> y en name cualquier cosa.<br>\nLas rutas son bastante dinámicas para poder gestionar <em>middlewares</em> de manera más cómoda y segura para nosotros(evitando datos de algún tipo que no queremos recibir).</p>\n<h4 id=\"usandoquerystring\">Usando query string</h4>\n<p>Ahora veamos un ejemplo con la segunda forma, que veréis que es muy parecido.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  console.log(req.query);\n  var newTitle = req.query.title;\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Hemos vuelto a dejar la ruta o path como estaba y en lugar de obtener el dato de title de los parámetros de la url, lo hacemos con la query y ¿como usamos esto? He puesto también un console.log para que veáis como recibimos los elementos de tipo query string. Simplemente poner</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/?title=Ninja\n</code></pre></div>\n<p>Al probar obtendríamos el mismo resultado, y si miráis el log de la consola veréis como recibe los parámetros de la query, como un objeto clave= valor<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.30.05.png\" alt=\"Middleware query string example\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.29.57.png\" alt=\"Log query string example\"></p>\n<h4 id=\"mtodosderespuesta\">Métodos de respuesta</h4>\n<p>Hasta ahora hemos estado centrados todo el rato en ala captura de la petición, es decir, en la parte <strong>request</strong> pero ¿que pasa con la respuesta? Vamos a ver algunos de los métodos de respuesta más usados, pero lo mejor es que miréis la <a href=\"http://expressjs.com/es/4x/api.html#res\">documentación</a> que vienen todos y muy bien explicados:</p>\n<ul>\n<li><strong>res.send</strong>: Lo hemos usado ya en algún ejemplo, responde como puede a lo que le pongas jejeje, funciona bien con buffer, strings, objetos, arrays(estos dos últimos los devolveria como un JSON)...</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.send('Hola Ninjas')\n</code></pre></div>\n<ul>\n<li><strong>res.render</strong>: También lo hemos usado, nos devuelve una página renderizada usando algún template y si acaso usando los parámetros que le pasemos</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.render('index',{title: 'Super Título Ninja'});\n</code></pre></div>\n<ul>\n<li><strong>res.json</strong>: Respuesta específica como JSON</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.json({ name: 'Batman'});\n</code></pre></div>\n<ul>\n<li><strong>res.download</strong>: Devuelve directamente un fichero, este sería el caso típico en el que nos aparece la ventana de <em>guardar</em> en el navegador</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.download('/rutaYNombreFichero.doc','nombreOpcionalDelFichero');\n</code></pre></div>\n<ul>\n<li><strong>res.redirect</strong>: Redireccionando al usuario a otro sitio con un código de estado 302 por defecto(esto se puede cambiar, más abajo lo veremos). En este caso tenemos varias opciones para la redirección.\n<ul>\n<li>Ruta relativa al root del usuario:</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.redirect('/root/path/algo');\n</code></pre></div>\n<ul>\n<li>Url absoluta:</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.redirect('http://urlnueva');\n</code></pre></div>\n<ul>\n<li>Pasandole también el código de estado:</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.redirect(301,'http://urlnueva');\n</code></pre></div>\n<ul>\n<li>Ruta según el path actual:</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.redirect('../ruta/algo')\n</code></pre></div>\n<ul>\n<li>También podemos hacer que vuelva a la página anterior:</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.redirect('back')\n</code></pre></div>\n</li>\n</ul>\n<p>Si miráis la documentación hay muchos más y todos estos pueden admitir más parámetros, con más opciones de configuración. Comentar que casi todas las opciones de respuesta soportan cambiar el código de estado, solo tenemos que encadenar métodos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.status(500).send('Error');\nres.status(200).render('index');\n</code></pre></div>\n<p>Muy cómodo si queremos devolver algún código específico que no sea el de por defecto de cada respuesta.<br>\nPoco a poco veremos como van saliendo distintos tipos de respuesta en los ejemplos que vayamos haciendo.</p>\n<h3 id=\"creandonuestrapropiaruta\">Creando nuestra propia ruta</h3>\n<p>Hasta ahora hemos estado trabajando con lo que ya nos había configurado <strong>express</strong>, pero ¿y si queremos crear nuestra propia ruta?¿Cuáles serían los pasos? Bien, pues vamos a verlos.<br>\nLo primero de todo es crearnos un fichero nuevo en la carpeta <em>routes</em>(para mantener el orden), por ejemplo lo voy a llamar <strong>ninjas.js</strong> y de momento le ponemos esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/heros', function(req, res, next) {\n  res.json({ninjas: \"Somos un montón de ninjas\"})\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Si os fijáis lo que hacemos es instanciar un <strong>Router</strong>, que es una de las formas de crear rutas para pasarselas a express. A este <em>router</em> le hemos indicado el método a usar, su path y su respuesta y por último lo hemos exportado como si de un módulo se tratara para así poder usarlo en cualquier parte de nuestra aplicación.<br>\nLo siguientes es irnos al <strong>app.js</strong> que, como ya comentamos en su momento, entre otras cosas tiene la instanciación de las rutas, y preparamos la nuestra, para ello lo primero es <em>requerirla</em>, y lo hacemos debajo de las otras</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var index = require('./routes/index');\nvar users = require('./routes/users');\nvar ninjas = require('./routes/ninjas');\n</code></pre></div>\n<p>Ya la tenemos disponible en nuestro <em>app.js</em> pero realmente todavia no le hemos indicado donde tiene que escuchar y que tiene que hacer, para hacerlo buscamos donde ha creado las otras y hacemos lo propio</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/', index);\napp.use('/users', users);\napp.use('/ninjas',ninjas);\n</code></pre></div>\n<p>Y listo con esto ya tendríamos nuestra propia ruta, como véis es bastante sencillo. Ahora vamos a probarla peeeeero ojo al dato, tenemos que tener en cuenta:</p>\n<ul>\n<li>La ruta o path que hemos puesto en el <strong>app.use</strong></li>\n<li>La ruta o path que hemos puesto en <strong>ninjas.js</strong></li>\n</ul>\n<p>Esto lo remarco porque realmente esto lo que esta haciendo es escuchar lo primero en el path <strong>/ninjas</strong> y según ese path lo que hace es indicarle al <strong>ninjas.js</strong> que es su turno (en plan enga majete a currar), pero claro este <em>router</em> tiene configurado también su propio path, es decir que a partir del path por el que ha sido convocado en el <em>app.use</em> tiene que cumplir el segundo que en este caso seria <strong>heros</strong>, por lo que la ruta quedariía así</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/ninjas/heros\n</code></pre></div>\n<p>Y esto nos devolvería un json<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-21-at-09.28.26.png\" alt=\"Own router example\"><br>\nUna vez que entiendes como funciona, ves que realmente es bastante sencillo configurar y trabajar con las rutas de express.</p>\n<p>Durante todo el post, ha estado apareciendo la palabra <strong>middleware</strong> pero , ¿que es exáctamente un middleware? Un <strong>middleware</strong> es un handler o manejador que responde a un tipo de petición o a todas. Básicamente es lo que hemos estado haciendo todo el rato. Veamos algunos detalles de su implementación.<br>\nSi os habéis fijado en nuestros middlewares que nos ha creado express, en los parámetros que recibe la función handler, tenemos esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function(req, res, next) {\n</code></pre></div>\n<p>Hemos visto que es <strong>req y res</strong> pero ¿que es next?, básicamente <strong>next</strong> es un método para indicar que continue hasta el siguiente middleware si no queremos terminar la ejecución. Supongamos por ejemplo que queremos comprobar el token de acceso de un usuario o sin ir más lejos si un usuario existe antes de tener acceso a ningún otro middleware. En este caso podríamos crear un middleware que en todas las peticiones compruebe cualquiera de los dos casos y a continuación una vez comprobado simplemente le diríamos que continuará al siguiente middleware para darle acceso a lo que realmente ha solicitado, es decir, acceso al middleware que nos ha mandado como <strong>request</strong>.<br>\nAhora vamos a ver un ejemplo muy sencillito para que se entienda mejor, pero antes comentar que si un middleware <strong>no responde de ninguna forma y no indica explicitamente que vaya al siguiente middleware no saldrá del handler en cuestión y nos dará timeout la petición</strong>. Vamos con el ejemplo, primero comprobemos que nos da timeout, para elloen nuestro <strong>app.js</strong> antes de indicar los middlewares ponemos los siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n});\n//Encima de este\napp.use('/', index);\n</code></pre></div>\n<p>Y comprobamos lo que pasa al acceder<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.11.37.png\" alt=\"Middleware timeout\"><br>\nEl log muestra nuestro nuevo middleware pero la ventana se queda a la espera de recibir algo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.12.01.png\" alt=\"Timeout example\"><br>\nAhora pongamos el <strong>next</strong> a ver que pasa</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n  next();\n});\n</code></pre></div>\n<p>Como véis en la consola ha pasado por el middleware(2 veces) y ha continuado hasta el siguiente middleware que coincide que es el <strong>index</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.14.56.png\" alt=\"Screen-Shot-2017-09-22-at-09.14.56\"><br>\nY como no hemos pasado en la queryString(que es como lo dejamos antes) solo nos aparece el <strong>welcome</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.17.10.png\" alt=\"Screen-Shot-2017-09-22-at-09.17.10\"><br>\nPero por lo menos vemos que ha continuado sin problemas.<br>\nImportante <strong>no podemos responder a un middleware y pasar al siguiente, lo que sea que queramos hacer tiene que ser al revés</strong>, es decir, no podemos responder 2 veces a la misma petición ya que el cliente no espera más de una respuesta, si en algún momento recibís en consola un log que ponga algo similar a <em>header ya envíado</em> o similar es porque estáis intentando responder dos veces.<br>\nLos middlewares podemos separarlos en varios tipos (como concepto de uso):</p>\n<ul>\n<li>Tenemos los middlewares a <strong>nivel de aplicación</strong>, es decir, los que ejecutamos en toda actividad de la app, y son los que normalmente deberían estar en el <strong>app.js</strong>. Acabamos de usar uno</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/', index);\n</code></pre></div>\n<ul>\n<li>Middleware a <strong>nivel de router</strong>: los que ponemos en la carpeta <strong>routes</strong> y responden a un tipo de petición o path específicos</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {}\n</code></pre></div>\n<ul>\n<li>Middleware <strong>de error</strong>: Estos los ponemos los últimos y como su nombre indica responderan cuando tengamos un error. Si miramos nuestro <strong>app.js</strong> vemos que tenemos uno al final. Se diferencian en que reciben un parámetro más <strong>err</strong>.</li>\n</ul>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n</code></pre></div>\n<p>Normalmente son llamados por nosotros pasándoselo al next, si os fijáis en el <strong>app.js</strong>, justo encima del middleware de error tenemos uno que captura todas las peticiones que no han coincidido y le pasa un mensaje de tipo 404 al middleware de error con <strong>next(err)</strong>(básicamente en cuanto a next le pasemos algo irá al handler de error)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n</code></pre></div>\n<ul>\n<li>Tenemos más <strong>middlewares oficiales</strong>, que básicamente son los mantenidos en el módulo <strong>connect</strong> que usa express. Podéis encontrar informacíon <a href=\"https://github.com/senchalabs/connect\">aquí</a>.</li>\n<li>Por último tenemos otros que llamaríamos <strong>middlewares de terceros</strong>, que son los creados y mantenidos por la comunidad, muchos de ellos aparecen en <a href=\"http://expressjs.com/en/resources/middleware.html\">esta página de express</a></li>\n</ul>\n<p>Creo que más o menos he comentado casi todo lo importante referente a los middlewares (ha sido un post más largo de lo habitual jejejejje), espero que a partir de ahora podáis hacer los vuestros sin problemas, en el siguiente post veremos un poco los templates y alguna cosa más. Sin mucho más nos veeemossss un abrazoooorrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Vamos a profundizar un poco en esto de las rutas, que es una de las partes centrales de express(y yo diría de Node casi)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLas rutas es lo que hemos llamado anteriormente métodos (el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"get"}]},{"type":"text","value":" que configuramos para probar), y como ya comentamos y vimos en la documentación oficial de express, tenemos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.method(urlPath,handler)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Siendo:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app:"}]},{"type":"text","value":" Ya vimos que es una instancia de express.Esta parte puede ser tambien "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":", ya veremos porque."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"method:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"GET:"}]},{"type":"text","value":" Se usa para pedir datos, y siempre que se le llame tiene que devolver lo mismo(siempre que la petición se haga de la misma forma)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"POST:"}]},{"type":"text","value":" Para crear algo, un objeto de nuestra app"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"PUT:"}]},{"type":"text","value":" Se usa para actualizar datos u objetos existentes."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"DELETE:"}]},{"type":"text","value":" Elimina datos u objetos existentes y al igual que el get siempre tiene que darnos el mismo resultado."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ALL:"}]},{"type":"text","value":" Con all, express aceptaría cualquiera de los anteriores, siempre y cuando el path coincida. Un posible uso sería para verificar credenciales si por ejemplo un token de sesión ha caducado y el usuario puede estar haciendo cualquier cosa, es decir, usando cualquiera de los otros métodos."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"urlPath:"}]},{"type":"text","value":" Será el path que si coincide con la petición que ha recibido Node ejecutará su "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"handler"}]},{"type":"text","value":" asociado"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"handler:"}]},{"type":"text","value":" Es el callback o función que se ejecuta si coincide el path."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un detalle "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"importante"}]},{"type":"text","value":" es que se comprueban las coincidencias de rutas en el orden que están escritas por lo que puede ser una buena opción si por ejemplo queremos comprobar si un usuario tiene permiso para acceder a cierta ruta o path."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Otro tipo de ruta o middleware es la de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ficheros estáticos"}]},{"type":"text","value":" como pueden ser imágenes,css o ficheros javascript, ya comenté un poco en el post anterior como era ya que por defecto la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"public"}]},{"type":"text","value":" estaba configurada como tal, veamoslo un poco en detalle"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use(express.static(path.join(__dirname, 'public')));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con esto lo que le estamos indicando a express y a node con este middleware es que todo lo que este en la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"public"}]},{"type":"text","value":" será servido como estático, ojo teniendo que usar la estructura de carpetas existentes, me refiero a que si debajo de public tenemos una carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"images"}]},{"type":"text","value":" el path deberia ser "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"urlRaiz/images/imagen.jpg"}]},{"type":"text","value":". Vamos a comprobarlo con el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"css"}]},{"type":"text","value":" que nos crea por defecto "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"express generator"}]},{"type":"text","value":", que en este caso esta dentro de la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"stylesheets"}]},{"type":"text","value":" y tiene el nombre "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"style.css"}]},{"type":"text","value":", entonces como hemos comentado la ruta sería (con nuestro proyecto iniciado claro está)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/stylesheets/style.css\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo que nos devolvería el fichero css en el navegador"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-19-at-08.51.39.png","alt":"Css static example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"También podemos indicarle a express que nos sirva los estáticos a través de un path o ruta virtual que nosotros le indiquemos, en lugar desde la ruta raiz. Si ponemos esta línea en el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" de nuestro proyecto (cambiandola por la que nos servía estáticos antes)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/ninja_static',express.static(path.join(__dirname, 'public')));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"entonces nuestra url cambiaría a"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/ninja_static/stylesheets/style.css\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto es muy útil si por ejemplo tenemos una estructura de carpetas de estáticos muy larga y queremos realemente acortar las url, podríamos por ejemplo cambiarlo por"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/ninjacss',express.static(path.join(__dirname, 'public/stylesheets')));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo que nos convierte la url a"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/ninjacss/style.css\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis podemos gestionar nuestras rutas como queramos para que sea más cómodo trabajar con ellas."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"rutasmiddlewaresconparmetros"},"children":[{"type":"text","value":"Rutas/Middlewares con parámetros"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hasta ahora habíamos visto siempre como trabajar con rutas digamos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"estáticas"}]},{"type":"text","value":" pero claro ninguna API es nunca tan simple, generalmente en la URL pasamos información para recibir un elemento específico, imaginemos por ejemplo que estamos creando una API que nos devuelva información sobre todos los superhéroes/villanos de los comics del mundo, ¿cuántos podrían ser? Miles como mínimo, lo que supondría tener que hacer una API con miles de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"middlewares"}]},{"type":"text","value":" ¿no?...por suerte no es necesario ya que sería algo inviable, ningún servicio aguantaría eso, lo que hacemos es que nuestro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"middleware"}]},{"type":"text","value":" reciba parámetros por ejemplo en la url, con este estilo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://heroapi.com/hero/57\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"o este por ejemplo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://heroapi.com/hero?name=batman\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tenemos varias formas de hacerlo, para finalmente buscar la información usando ese parámetro, todo en el mismo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"middleware"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn general tenemos cuatro formas de hacerlo:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"En la propia ruta: /hero/57"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Usando "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"query string"}]},{"type":"text","value":": /hero?name=batman, se conoce "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"query string"}]},{"type":"text","value":" a lo que está destrás de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"?"}]},{"type":"text","value":" y son elementos de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"variable=valor"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Puede ir en el cuerpo(body) de la petición, esto generalmente se usa para peticiones de tipo POST o PUT, ya que al almacenar/actualizar solemos enviar muchos datos y pasarlo por "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"query string"}]},{"type":"text","value":" puede ser casi imposible."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Otra opción puede ser la cabecera, aunque esta opción exista simplemente porque podemos acceder a la cabecera desde el middleware, pero no se usa para datos triviales (como buscar un héroe), si no para datos como token de autenticación, formatos y cosas así."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h4","properties":{"id":"enlaruta"},"children":[{"type":"text","value":"En la ruta"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Empecemos con un ejemplo con usando la ruta, nos vamos a nuestro proyecto de ejemplo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ninja_project"}]},{"type":"text","value":" y vamos a modificar la ruta del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":" poniéndole un parámetro para cambiar el título. Quedaría así:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/:title', function(req, res, next) {\n  var newTitle = req.params.title\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis a la ruta le hemos puesto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":":title"}]},{"type":"text","value":" y luego simplemente hemos sacado esa información de los parámetros (params) de la petición (request)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi ejecutamos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm start"}]},{"type":"text","value":" y probamos por ejemplo con"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/Ninja\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tendríamos este resultado"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.21.56.png","alt":"Middleware route params example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nUsando las rutas como paso de parámetros tenemos varias opciones, para por ejemplo si queremos que el parámetro sea opcional(si probáis sin poner /Ninja os daria un error el ejemplo anterior) ponemos la ruta de esta manera"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/:title?', function(req, res, next) {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"También es posible usar expresiones regulares para que por ejemplo solo admita números"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/:id([0-9]+)', function(req, res, next) {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y es posible poner varios"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/:type(villain|hero)/data/:name)', function(req, res, next) {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esta aceptaría en type solo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"villain o hero"}]},{"type":"text","value":" y en name cualquier cosa."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLas rutas son bastante dinámicas para poder gestionar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"middlewares"}]},{"type":"text","value":" de manera más cómoda y segura para nosotros(evitando datos de algún tipo que no queremos recibir)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h4","properties":{"id":"usandoquerystring"},"children":[{"type":"text","value":"Usando query string"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora veamos un ejemplo con la segunda forma, que veréis que es muy parecido."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  console.log(req.query);\n  var newTitle = req.query.title;\n  res.render('index', { title: newTitle });\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hemos vuelto a dejar la ruta o path como estaba y en lugar de obtener el dato de title de los parámetros de la url, lo hacemos con la query y ¿como usamos esto? He puesto también un console.log para que veáis como recibimos los elementos de tipo query string. Simplemente poner"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/?title=Ninja\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Al probar obtendríamos el mismo resultado, y si miráis el log de la consola veréis como recibe los parámetros de la query, como un objeto clave= valor"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.30.05.png","alt":"Middleware query string example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.29.57.png","alt":"Log query string example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h4","properties":{"id":"mtodosderespuesta"},"children":[{"type":"text","value":"Métodos de respuesta"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hasta ahora hemos estado centrados todo el rato en ala captura de la petición, es decir, en la parte "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"request"}]},{"type":"text","value":" pero ¿que pasa con la respuesta? Vamos a ver algunos de los métodos de respuesta más usados, pero lo mejor es que miréis la "},{"type":"element","tagName":"a","properties":{"href":"http://expressjs.com/es/4x/api.html#res"},"children":[{"type":"text","value":"documentación"}]},{"type":"text","value":" que vienen todos y muy bien explicados:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.send"}]},{"type":"text","value":": Lo hemos usado ya en algún ejemplo, responde como puede a lo que le pongas jejeje, funciona bien con buffer, strings, objetos, arrays(estos dos últimos los devolveria como un JSON)..."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.send('Hola Ninjas')\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.render"}]},{"type":"text","value":": También lo hemos usado, nos devuelve una página renderizada usando algún template y si acaso usando los parámetros que le pasemos"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.render('index',{title: 'Super Título Ninja'});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.json"}]},{"type":"text","value":": Respuesta específica como JSON"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.json({ name: 'Batman'});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.download"}]},{"type":"text","value":": Devuelve directamente un fichero, este sería el caso típico en el que nos aparece la ventana de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"guardar"}]},{"type":"text","value":" en el navegador"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.download('/rutaYNombreFichero.doc','nombreOpcionalDelFichero');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.redirect"}]},{"type":"text","value":": Redireccionando al usuario a otro sitio con un código de estado 302 por defecto(esto se puede cambiar, más abajo lo veremos). En este caso tenemos varias opciones para la redirección.\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Ruta relativa al root del usuario:"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.redirect('/root/path/algo');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Url absoluta:"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.redirect('http://urlnueva');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Pasandole también el código de estado:"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.redirect(301,'http://urlnueva');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Ruta según el path actual:"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.redirect('../ruta/algo')\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"También podemos hacer que vuelva a la página anterior:"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.redirect('back')\n"}]}]}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si miráis la documentación hay muchos más y todos estos pueden admitir más parámetros, con más opciones de configuración. Comentar que casi todas las opciones de respuesta soportan cambiar el código de estado, solo tenemos que encadenar métodos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.status(500).send('Error');\nres.status(200).render('index');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Muy cómodo si queremos devolver algún código específico que no sea el de por defecto de cada respuesta."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPoco a poco veremos como van saliendo distintos tipos de respuesta en los ejemplos que vayamos haciendo."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"creandonuestrapropiaruta"},"children":[{"type":"text","value":"Creando nuestra propia ruta"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hasta ahora hemos estado trabajando con lo que ya nos había configurado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"express"}]},{"type":"text","value":", pero ¿y si queremos crear nuestra propia ruta?¿Cuáles serían los pasos? Bien, pues vamos a verlos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo primero de todo es crearnos un fichero nuevo en la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"routes"}]},{"type":"text","value":"(para mantener el orden), por ejemplo lo voy a llamar "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" y de momento le ponemos esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/heros', function(req, res, next) {\n  res.json({ninjas: \"Somos un montón de ninjas\"})\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis lo que hacemos es instanciar un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Router"}]},{"type":"text","value":", que es una de las formas de crear rutas para pasarselas a express. A este "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":" le hemos indicado el método a usar, su path y su respuesta y por último lo hemos exportado como si de un módulo se tratara para así poder usarlo en cualquier parte de nuestra aplicación."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo siguientes es irnos al "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" que, como ya comentamos en su momento, entre otras cosas tiene la instanciación de las rutas, y preparamos la nuestra, para ello lo primero es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerirla"}]},{"type":"text","value":", y lo hacemos debajo de las otras"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var index = require('./routes/index');\nvar users = require('./routes/users');\nvar ninjas = require('./routes/ninjas');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya la tenemos disponible en nuestro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" pero realmente todavia no le hemos indicado donde tiene que escuchar y que tiene que hacer, para hacerlo buscamos donde ha creado las otras y hacemos lo propio"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/', index);\napp.use('/users', users);\napp.use('/ninjas',ninjas);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y listo con esto ya tendríamos nuestra propia ruta, como véis es bastante sencillo. Ahora vamos a probarla peeeeero ojo al dato, tenemos que tener en cuenta:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"La ruta o path que hemos puesto en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.use"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"La ruta o path que hemos puesto en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ninjas.js"}]}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto lo remarco porque realmente esto lo que esta haciendo es escuchar lo primero en el path "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"/ninjas"}]},{"type":"text","value":" y según ese path lo que hace es indicarle al "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" que es su turno (en plan enga majete a currar), pero claro este "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":" tiene configurado también su propio path, es decir que a partir del path por el que ha sido convocado en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"app.use"}]},{"type":"text","value":" tiene que cumplir el segundo que en este caso seria "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"heros"}]},{"type":"text","value":", por lo que la ruta quedariía así"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/ninjas/heros\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y esto nos devolvería un json"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-21-at-09.28.26.png","alt":"Own router example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nUna vez que entiendes como funciona, ves que realmente es bastante sencillo configurar y trabajar con las rutas de express."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Durante todo el post, ha estado apareciendo la palabra "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"middleware"}]},{"type":"text","value":" pero , ¿que es exáctamente un middleware? Un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"middleware"}]},{"type":"text","value":" es un handler o manejador que responde a un tipo de petición o a todas. Básicamente es lo que hemos estado haciendo todo el rato. Veamos algunos detalles de su implementación."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi os habéis fijado en nuestros middlewares que nos ha creado express, en los parámetros que recibe la función handler, tenemos esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"function(req, res, next) {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hemos visto que es "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"req y res"}]},{"type":"text","value":" pero ¿que es next?, básicamente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"next"}]},{"type":"text","value":" es un método para indicar que continue hasta el siguiente middleware si no queremos terminar la ejecución. Supongamos por ejemplo que queremos comprobar el token de acceso de un usuario o sin ir más lejos si un usuario existe antes de tener acceso a ningún otro middleware. En este caso podríamos crear un middleware que en todas las peticiones compruebe cualquiera de los dos casos y a continuación una vez comprobado simplemente le diríamos que continuará al siguiente middleware para darle acceso a lo que realmente ha solicitado, es decir, acceso al middleware que nos ha mandado como "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"request"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora vamos a ver un ejemplo muy sencillito para que se entienda mejor, pero antes comentar que si un middleware "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"no responde de ninguna forma y no indica explicitamente que vaya al siguiente middleware no saldrá del handler en cuestión y nos dará timeout la petición"}]},{"type":"text","value":". Vamos con el ejemplo, primero comprobemos que nos da timeout, para elloen nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" antes de indicar los middlewares ponemos los siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n});\n//Encima de este\napp.use('/', index);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y comprobamos lo que pasa al acceder"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.11.37.png","alt":"Middleware timeout"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEl log muestra nuestro nuevo middleware pero la ventana se queda a la espera de recibir algo"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.12.01.png","alt":"Timeout example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora pongamos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"next"}]},{"type":"text","value":" a ver que pasa"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/', function(req,res,next){\n  console.log('MIddleware sin respuesta');\n  next();\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis en la consola ha pasado por el middleware(2 veces) y ha continuado hasta el siguiente middleware que coincide que es el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.14.56.png","alt":"Screen-Shot-2017-09-22-at-09.14.56"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nY como no hemos pasado en la queryString(que es como lo dejamos antes) solo nos aparece el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"welcome"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.17.10.png","alt":"Screen-Shot-2017-09-22-at-09.17.10"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPero por lo menos vemos que ha continuado sin problemas."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nImportante "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"no podemos responder a un middleware y pasar al siguiente, lo que sea que queramos hacer tiene que ser al revés"}]},{"type":"text","value":", es decir, no podemos responder 2 veces a la misma petición ya que el cliente no espera más de una respuesta, si en algún momento recibís en consola un log que ponga algo similar a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"header ya envíado"}]},{"type":"text","value":" o similar es porque estáis intentando responder dos veces."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLos middlewares podemos separarlos en varios tipos (como concepto de uso):"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Tenemos los middlewares a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"nivel de aplicación"}]},{"type":"text","value":", es decir, los que ejecutamos en toda actividad de la app, y son los que normalmente deberían estar en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":". Acabamos de usar uno"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/', index);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Middleware a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"nivel de router"}]},{"type":"text","value":": los que ponemos en la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"routes"}]},{"type":"text","value":" y responden a un tipo de petición o path específicos"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Middleware "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"de error"}]},{"type":"text","value":": Estos los ponemos los últimos y como su nombre indica responderan cuando tengamos un error. Si miramos nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" vemos que tenemos uno al final. Se diferencian en que reciben un parámetro más "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"err"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Normalmente son llamados por nosotros pasándoselo al next, si os fijáis en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":", justo encima del middleware de error tenemos uno que captura todas las peticiones que no han coincidido y le pasa un mensaje de tipo 404 al middleware de error con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"next(err)"}]},{"type":"text","value":"(básicamente en cuanto a next le pasemos algo irá al handler de error)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Tenemos más "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"middlewares oficiales"}]},{"type":"text","value":", que básicamente son los mantenidos en el módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"connect"}]},{"type":"text","value":" que usa express. Podéis encontrar informacíon "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/senchalabs/connect"},"children":[{"type":"text","value":"aquí"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Por último tenemos otros que llamaríamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"middlewares de terceros"}]},{"type":"text","value":", que son los creados y mantenidos por la comunidad, muchos de ellos aparecen en "},{"type":"element","tagName":"a","properties":{"href":"http://expressjs.com/en/resources/middleware.html"},"children":[{"type":"text","value":"esta página de express"}]}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Creo que más o menos he comentado casi todo lo importante referente a los middlewares (ha sido un post más largo de lo habitual jejejejje), espero que a partir de ahora podáis hacer los vuestros sin problemas, en el siguiente post veremos un poco los templates y alguna cosa más. Sin mucho más nos veeemossss un abrazoooorrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"rutasmiddlewaresconparmetros","heading":"Rutas/Middlewares con parámetros","items":[{"id":"enlaruta","heading":"En la ruta"},{"id":"usandoquerystring","heading":"Usando query string"},{"id":"mtodosderespuesta","heading":"Métodos de respuesta"}]},{"id":"creandonuestrapropiaruta","heading":"Creando nuestra propia ruta"}]},"featureImageSharp":{"base":"nodebaner-5.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-5.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":4,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner-5.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/65d8c/nodebaner-5.jpg 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/c5f21/nodebaner-5.jpg 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner-5.jpg 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/81a53/nodebaner-5.jpg 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-5.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner-5.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/dc8f3/nodebaner-5.webp 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/2db4b/nodebaner-5.webp 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner-5.webp 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/f5845/nodebaner-5.webp 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-5.webp 1680w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"prev":{"id":"Ghost__Post__5a338158333e0f134c248f36","title":"Don't stop the party: Node JS(X) Templates o Vistas","slug":"dont-stop-the-party-node-js-x-templates-o-vistas","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-4-1.jpg","excerpt":"Ahora le toca el turno a las vistas o templates, aunque realmente este tema es\nmuy amplio porque express admite multitud de engines de templates distintos. En\nla documentación oficial\n[https://github.com/expressjs/express/wiki#template-engines] tenéis todos los\nque soporta y como se usan, veremos ejemplos con ejs porque es muy típico pero\nrealmente podéis usar el que queráis.\nComentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor\npara servirlas al cliente ya que aumenta","custom_excerpt":null,"visibility":"public","created_at_pretty":"22 Sep 2017","published_at_pretty":"5 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-22T20:35:52.000+02:00","published_at":"2017-10-05T10:00:00.000+02:00","updated_at":"2018-01-22T09:39:22.000+01:00","meta_title":"Don't stop the party: Node JS(X) Templates o Vistas","meta_description":"Hablaremos de las vistas o templates con Express y de como lo podemos usar para hacer front basado en renderizado en servidor. Sería la E del stack MEAN","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Ahora le toca el turno a las vistas o templates, aunque realmente este tema es\nmuy amplio porque express admite multitud de engines de templates distintos. En\nla documentación oficial\n[https://github.com/expressjs/express/wiki#template-engines] tenéis todos los\nque soporta y como se usan, veremos ejemplos con ejs porque es muy típico pero\nrealmente podéis usar el que queráis.\nComentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor\npara servirlas al cliente ya que aumentas la carga de trabajo del servidor,\nprefiero usar Node+Express como API Rest y para las vistas usar directamente \nAngularJS, ReactJS o similar pero al final depende un poco del proyecto o\naplicación que estemos realizando, si es una página simple, casi como las que\nhemos visto de ejemplo, usamos los templates y ale a correr.\nBueno después de quejarme un poco vamos a continuar....como he comentado\ntrabajaremos un poco con ejs y para ello lo primero que tenemos que hacer es\ninstalar el engine.\n\nnpm install ejs --save\n\n\nRecordad usamos --save para que al instalar el módulo lo indique también en el \npackage.json y poder llevar control de versiones (y ya de paso si movemos la app\nque lo instale directamente)\nAntes de continuar, os cuento, nosotros vamos a modificar nuestro proyecto de\nexpress actual para cambiar el engine pero si de primeras ya sabéis que váis a\nusar un engine en concreto, si recordáis se lo podíamos indicar a \nexpress_generator para que configure él directamente, si probáis el comando:\n\nexpress -h\n\n\nveréis las opciones que tenemos\n\nAún así no penséis que cambiar de uno a otro es muy difícil solo tenemos que\nsaber que caracteriza a cada uno, o más bien como se compone cada uno. En el\ncaso de ejs es que realmente tu realizas la composición sobre código HTML,\nsupongo que es una de las claves de su aceptación, básicamente es lo mismo que\nya se estaba haciendo desde hace años pero con vitaminas.\n\nEl primer cambio que haremos una vez instalado es cambiar el engine en el app.js\n, para ello vamos a cambiar la línea\n\napp.set('view engine', 'jade');\n\n\npor esta otra (solo cambiando jade....superdifícil)\n\napp.set('view engine', 'ejs');\n\n\nYa tenemos el primer paso, lo siguiente que haremos será cambiar la vista index \npor ejemplo(solo cambiaremos una para que veáis de que va). Priemo eliminamos el \nindex.jade de la carpeta views y creamos otro que sea index.ejs. Una vez creado\nvamos a empezar por un código simple de HTML(mu feo lo sé es para probar solo)\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n</html>\n\n\nEsto nos muestra ya lo siguiente\n\nYa funciona. Ahora vamos a prepararlo para que use la variable title que le\npasabamos desde el middleware.\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%= title %></p>\n  </body>\n</html>\n\n\nSi os fijáis la variable esta puesta directamente entre <%= %>, fácil ¿verdad?.\nAhora vamos a probarlo, recordar que teníamos configurado el middleware para que\nusara los datos recibidos de la query string, por lo que la URL debería ser algo\nsimilar a\n\nhttp://localhost:3000/?title=Ninjas\n\n\nY nos debería mostrar algo similar a\n\nVoilá supersencillo. Ahora veamos alguna cosa más que podemos hacer con ejs.\nEn el ejemplo hemos usado <%= %> para trabajar con variables, pero claro si\nqueremos poner código HTML como variable, ¿funcionaría? Veamos que pasa.\nCambiamos la variable title que le mandamos a la vista, en nuestro index.js \ncambias res.render por\n\nres.render('index', { title: '<h2>' + newTitle + '</h2>' });\n\n\nY ahora veamos el resultado\n\nUps!!! nos aparace todo literal, eso es porque con <%= %> básicamente\nconseguimos que nos transforme todo a literal(en este caso un string), pero ejs \nestá preparado para esto, solo tenemos que cambiar los tags en nuestro index.ejs\n, básicamente cambiamos el igual por un guión y listo\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n  </body>\n</html>\n\n\nAhora ya tendríamos algo similar a esto\n\nAcabamos de ver como podemos pasarle estructuras de HTML directamente a la\nvista, pero todavía podemos hacer más cosas interesantes. Una de las ventajas de \nejs es que podemos usar código javaScript directamente en la vista, vamos a ver\nalgunos ejemplos\nEmpecemos por ver como podríamos hacer un condicional, cambiémos nuestro \nindex.ejs por esto\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n<% if (title === 'Ninjas'){ %>\n       <p>Somos Ninjas</p>\n<%}else{%>\n      <p>Te has equivocadooooo</p> \n<%}%>\n  </body>\n</html>\n\n\nY que no se nos olvide cambiar en nuestro index.js la línea de render por\n\nres.render('index', { title: newTitle});\n\n\nSolo es quitarle los tags HTML.\nAhora vamos a probarlo, pongamos por ejemplo esto en la url\nhttp://localhost:3000/?title=Superman\n\nVemos como al no cumplir la condición sale la segunda opción, ahora probemos con\nnuestro title=Ninjas\n\nPor último vamos a probar a trabajar con un array de elementos. Creemos lo\nprimero nuestro objeto array en index.js, cambiando el ya conocido res.render \npor\n\nres.render('index', { \n    title: newTitle,\n    superHeros: [{name: 'Dr. Manhattan'},{name: 'Superman'},{name: 'El Comendiante'}]\n  });\n\n\nYa tenemos nuestro array de elementos, ahora hagamos que la vista trabaje con\nellos, en index.ejs añadimos lo siguiente\n\n<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n<% if (title === 'Ninjas'){ %>\n       <p>Somos Ninjas</p>\n       \n       <% superHeros.forEach(function(hero){ %>\n        \n         <p><%= hero.name %></p>\n        \n       <%})%>\n       \n<%}else{%>\n      <p>Te has equivocadooooo</p> \n<%}%>\n  </body>\n</html>\n\n\nSi os fijáis hemos recorrido directamente el objeto superHeros y hemos mostrado\nla propiedad name de cada uno. Veamos lo que pasa cuando usamos title=Ninjas\n\nVoilá, como véis es relativamente sencillo utilizar templates ejs, esto ha sido\nsolo una pequeña muestra de como podemos ir trabajando con ellos pero las\nposibilidades son infinitas (y también recordar que tenemos multitud de engines\ndistintos).\n\nHasta aquí lo que quería comentar sobre los templates, en los siguientes post\nveremos como gestionar autenticación en nuestra API, uso de Promesas....y varias\ncosas más, nos veeemossss\n\nUn abrazooorrr","html":"<!--kg-card-begin: markdown--><p>Ahora le toca el turno a las vistas o templates, aunque realmente este tema es muy amplio porque <strong>express</strong> admite multitud de <em>engines</em> de templates distintos. En la <a href=\"https://github.com/expressjs/express/wiki#template-engines\">documentación oficial</a> tenéis todos los que soporta y como se usan, veremos ejemplos con <em>ejs</em> porque es muy típico pero realmente podéis usar el que queráis.<br>\nComentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor para servirlas al cliente ya que aumentas la carga de trabajo del servidor, prefiero usar Node+Express como API Rest y para las vistas usar directamente <strong>AngularJS</strong>, <strong>ReactJS</strong> o similar pero al final depende un poco del proyecto o aplicación que estemos realizando, si es una página simple, casi como las que hemos visto de ejemplo, usamos los templates y ale a correr.<br>\nBueno después de quejarme un poco vamos a continuar....como he comentado trabajaremos un poco con <strong>ejs</strong> y para ello lo primero que tenemos que hacer es instalar el engine.</p>\n<pre><code>npm install ejs --save\n</code></pre>\n<p>Recordad usamos <strong>--save</strong> para que al instalar el módulo lo indique también en el <strong>package.json</strong> y poder llevar control de versiones (y ya de paso si movemos la app que lo instale directamente)<br>\nAntes de continuar, os cuento, nosotros vamos a modificar nuestro proyecto de express actual para cambiar el <em>engine</em> pero si de primeras ya sabéis que váis a usar un engine en concreto, si recordáis se lo podíamos indicar a <strong>express_generator</strong> para que configure él directamente, si probáis el comando:</p>\n<pre><code>express -h\n</code></pre>\n<p>veréis las opciones que tenemos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.03.31.png\" alt=\"Express help\"><br>\nAún así no penséis que cambiar de uno a otro es muy difícil solo tenemos que saber que caracteriza a cada uno, o más bien como se compone cada uno. En el caso de <strong>ejs</strong> es que realmente tu realizas la composición sobre código HTML, supongo que es una de las claves de su aceptación, básicamente es lo mismo que ya se estaba haciendo desde hace años pero con vitaminas.</p>\n<p>El primer cambio que haremos una vez instalado es cambiar el <em>engine</em> en el <strong>app.js</strong>, para ello vamos a cambiar la línea</p>\n<pre><code>app.set('view engine', 'jade');\n</code></pre>\n<p>por esta otra (solo cambiando jade....superdifícil)</p>\n<pre><code>app.set('view engine', 'ejs');\n</code></pre>\n<p>Ya tenemos el primer paso, lo siguiente que haremos será cambiar la vista <strong>index</strong> por ejemplo(solo cambiaremos una para que veáis de que va). Priemo eliminamos el <strong>index.jade</strong> de la carpeta <em>views</em> y creamos otro que sea <strong>index.ejs</strong>. Una vez creado vamos a empezar por un código simple de HTML(mu feo lo sé es para probar solo)</p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;h1&gt;NinjaTitle&lt;/h1&gt;\n  &lt;/head&gt;\n&lt;/html&gt;\n</code></pre>\n<p>Esto nos muestra ya lo siguiente<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.43.35.png\" alt=\"Ejs Template Index change\"><br>\nYa funciona. Ahora vamos a prepararlo para que use la variable <em>title</em> que le pasabamos desde el middleware.</p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;h1&gt;NinjaTitle&lt;/h1&gt;\n  &lt;/head&gt;\n  &lt;body&gt;\n      &lt;p&gt;Bienvenidos a vuestro template ejs &lt;%= title %&gt;&lt;/p&gt;\n  &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>Si os fijáis la variable esta puesta directamente entre <strong>&lt;%= %&gt;</strong>, fácil ¿verdad?. Ahora vamos a probarlo, recordar que teníamos configurado el middleware para que usara los datos recibidos de la <em>query string</em>, por lo que la URL debería ser algo similar a</p>\n<pre><code>http://localhost:3000/?title=Ninjas\n</code></pre>\n<p>Y nos debería mostrar algo similar a<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.50.14.png\" alt=\"Ejs template title done\"><br>\nVoilá supersencillo. Ahora veamos alguna cosa más que podemos hacer con <strong>ejs</strong>.<br>\nEn el ejemplo hemos usado &lt;%= %&gt; para trabajar con variables, pero claro si queremos poner código HTML como variable, ¿funcionaría? Veamos que pasa.<br>\nCambiamos la variable title que le mandamos a la vista, en nuestro <strong>index.js</strong> cambias <strong>res.render</strong> por</p>\n<pre><code>res.render('index', { title: '&lt;h2&gt;' + newTitle + '&lt;/h2&gt;' });\n</code></pre>\n<p>Y ahora veamos el resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/html_tags.PNG\" alt=\"html_tags\"><br>\nUps!!! nos aparace todo literal, eso es porque con <strong>&lt;%= %&gt;</strong> básicamente conseguimos que nos transforme todo a literal(en este caso un string), pero <strong>ejs</strong> está preparado para esto, solo tenemos que cambiar los tags en nuestro <strong>index.ejs</strong>, básicamente cambiamos el igual por un guión y listo</p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;h1&gt;NinjaTitle&lt;/h1&gt;\n  &lt;/head&gt;\n  &lt;body&gt;\n      &lt;p&gt;Bienvenidos a vuestro template ejs &lt;%- title %&gt;&lt;/p&gt;\n  &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>Ahora ya tendríamos algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-26-at-21.44.21.png\" alt=\"Html in ejs template\"><br>\nAcabamos de ver como podemos pasarle estructuras de HTML directamente a la vista, pero todavía podemos hacer más cosas interesantes. Una de las ventajas de <strong>ejs</strong> es que podemos usar código javaScript directamente en la vista, vamos a ver algunos ejemplos<br>\nEmpecemos por ver como podríamos hacer un condicional, cambiémos nuestro <strong>index.ejs</strong> por esto</p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;h1&gt;NinjaTitle&lt;/h1&gt;\n  &lt;/head&gt;\n  &lt;body&gt;\n      &lt;p&gt;Bienvenidos a vuestro template ejs &lt;%- title %&gt;&lt;/p&gt;\n&lt;% if (title === 'Ninjas'){ %&gt;\n       &lt;p&gt;Somos Ninjas&lt;/p&gt;\n&lt;%}else{%&gt;\n      &lt;p&gt;Te has equivocadooooo&lt;/p&gt; \n&lt;%}%&gt;\n  &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>Y que no se nos olvide cambiar en nuestro <strong>index.js</strong> la línea de <strong>render</strong> por</p>\n<pre><code>res.render('index', { title: newTitle});\n</code></pre>\n<p>Solo es quitarle los <em>tags</em> HTML.<br>\nAhora vamos a probarlo, pongamos por ejemplo esto en la url<br>\n<strong><a href=\"http://localhost:3000/?title=Superman\">http://localhost:3000/?title=Superman</a></strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.12.54.png\" alt=\"Wrong Title\"><br>\nVemos como al no cumplir la condición sale la segunda opción, ahora probemos con nuestro <em>title=Ninjas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.15.15.png\" alt=\"Ninjas Title\"><br>\nPor último vamos a probar a trabajar con un <em>array</em> de elementos. Creemos lo primero nuestro objeto array en <strong>index.js</strong>, cambiando el ya conocido <strong>res.render</strong> por</p>\n<pre><code>res.render('index', { \n    title: newTitle,\n    superHeros: [{name: 'Dr. Manhattan'},{name: 'Superman'},{name: 'El Comendiante'}]\n  });\n</code></pre>\n<p>Ya tenemos nuestro array de elementos, ahora hagamos que la vista trabaje con ellos, en <strong>index.ejs</strong> añadimos lo siguiente</p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;h1&gt;NinjaTitle&lt;/h1&gt;\n  &lt;/head&gt;\n  &lt;body&gt;\n      &lt;p&gt;Bienvenidos a vuestro template ejs &lt;%- title %&gt;&lt;/p&gt;\n&lt;% if (title === 'Ninjas'){ %&gt;\n       &lt;p&gt;Somos Ninjas&lt;/p&gt;\n       \n       &lt;% superHeros.forEach(function(hero){ %&gt;\n        \n         &lt;p&gt;&lt;%= hero.name %&gt;&lt;/p&gt;\n        \n       &lt;%})%&gt;\n       \n&lt;%}else{%&gt;\n      &lt;p&gt;Te has equivocadooooo&lt;/p&gt; \n&lt;%}%&gt;\n  &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>Si os fijáis hemos recorrido directamente el objeto <strong>superHeros</strong> y hemos mostrado la propiedad <strong>name</strong> de cada uno. Veamos lo que pasa cuando usamos <strong>title=Ninjas</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.27.49.png\" alt=\"Array in ejs\"><br>\nVoilá, como véis es relativamente sencillo utilizar templates ejs, esto ha sido solo una pequeña muestra de como podemos ir trabajando con ellos pero las posibilidades son infinitas (y también recordar que tenemos multitud de engines distintos).</p>\n<p>Hasta aquí lo que quería comentar sobre los templates, en los siguientes post veremos como gestionar autenticación en nuestra API, uso de Promesas....y varias cosas más, nos veeemossss</p>\n<p>Un abrazooorrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-x-templates-o-vistas/","canonical_url":null,"uuid":"457e53cd-07e8-4675-bdcc-0a47312d390b","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59c5580858177700014ca363","reading_time":5,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Ahora le toca el turno a las vistas o templates, aunque realmente este tema es muy amplio porque <strong>express</strong> admite multitud de <em>engines</em> de templates distintos. En la <a href=\"https://github.com/expressjs/express/wiki#template-engines\">documentación oficial</a> tenéis todos los que soporta y como se usan, veremos ejemplos con <em>ejs</em> porque es muy típico pero realmente podéis usar el que queráis.<br>\nComentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor para servirlas al cliente ya que aumentas la carga de trabajo del servidor, prefiero usar Node+Express como API Rest y para las vistas usar directamente <strong>AngularJS</strong>, <strong>ReactJS</strong> o similar pero al final depende un poco del proyecto o aplicación que estemos realizando, si es una página simple, casi como las que hemos visto de ejemplo, usamos los templates y ale a correr.<br>\nBueno después de quejarme un poco vamos a continuar....como he comentado trabajaremos un poco con <strong>ejs</strong> y para ello lo primero que tenemos que hacer es instalar el engine.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install ejs --save\n</code></pre></div>\n<p>Recordad usamos <strong>--save</strong> para que al instalar el módulo lo indique también en el <strong>package.json</strong> y poder llevar control de versiones (y ya de paso si movemos la app que lo instale directamente)<br>\nAntes de continuar, os cuento, nosotros vamos a modificar nuestro proyecto de express actual para cambiar el <em>engine</em> pero si de primeras ya sabéis que váis a usar un engine en concreto, si recordáis se lo podíamos indicar a <strong>express_generator</strong> para que configure él directamente, si probáis el comando:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">express -h\n</code></pre></div>\n<p>veréis las opciones que tenemos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.03.31.png\" alt=\"Express help\"><br>\nAún así no penséis que cambiar de uno a otro es muy difícil solo tenemos que saber que caracteriza a cada uno, o más bien como se compone cada uno. En el caso de <strong>ejs</strong> es que realmente tu realizas la composición sobre código HTML, supongo que es una de las claves de su aceptación, básicamente es lo mismo que ya se estaba haciendo desde hace años pero con vitaminas.</p>\n<p>El primer cambio que haremos una vez instalado es cambiar el <em>engine</em> en el <strong>app.js</strong>, para ello vamos a cambiar la línea</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.set('view engine', 'jade');\n</code></pre></div>\n<p>por esta otra (solo cambiando jade....superdifícil)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.set('view engine', 'ejs');\n</code></pre></div>\n<p>Ya tenemos el primer paso, lo siguiente que haremos será cambiar la vista <strong>index</strong> por ejemplo(solo cambiaremos una para que veáis de que va). Priemo eliminamos el <strong>index.jade</strong> de la carpeta <em>views</em> y creamos otro que sea <strong>index.ejs</strong>. Una vez creado vamos a empezar por un código simple de HTML(mu feo lo sé es para probar solo)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;!DOCTYPE html>\n&#x3C;html>\n  &#x3C;head>\n    &#x3C;h1>NinjaTitle&#x3C;/h1>\n  &#x3C;/head>\n&#x3C;/html>\n</code></pre></div>\n<p>Esto nos muestra ya lo siguiente<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.43.35.png\" alt=\"Ejs Template Index change\"><br>\nYa funciona. Ahora vamos a prepararlo para que use la variable <em>title</em> que le pasabamos desde el middleware.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;!DOCTYPE html>\n&#x3C;html>\n  &#x3C;head>\n    &#x3C;h1>NinjaTitle&#x3C;/h1>\n  &#x3C;/head>\n  &#x3C;body>\n      &#x3C;p>Bienvenidos a vuestro template ejs &#x3C;%= title %>&#x3C;/p>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre></div>\n<p>Si os fijáis la variable esta puesta directamente entre <strong>&#x3C;%= %></strong>, fácil ¿verdad?. Ahora vamos a probarlo, recordar que teníamos configurado el middleware para que usara los datos recibidos de la <em>query string</em>, por lo que la URL debería ser algo similar a</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/?title=Ninjas\n</code></pre></div>\n<p>Y nos debería mostrar algo similar a<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.50.14.png\" alt=\"Ejs template title done\"><br>\nVoilá supersencillo. Ahora veamos alguna cosa más que podemos hacer con <strong>ejs</strong>.<br>\nEn el ejemplo hemos usado &#x3C;%= %> para trabajar con variables, pero claro si queremos poner código HTML como variable, ¿funcionaría? Veamos que pasa.<br>\nCambiamos la variable title que le mandamos a la vista, en nuestro <strong>index.js</strong> cambias <strong>res.render</strong> por</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.render('index', { title: '&#x3C;h2>' + newTitle + '&#x3C;/h2>' });\n</code></pre></div>\n<p>Y ahora veamos el resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/html_tags.PNG\" alt=\"html_tags\"><br>\nUps!!! nos aparace todo literal, eso es porque con <strong>&#x3C;%= %></strong> básicamente conseguimos que nos transforme todo a literal(en este caso un string), pero <strong>ejs</strong> está preparado para esto, solo tenemos que cambiar los tags en nuestro <strong>index.ejs</strong>, básicamente cambiamos el igual por un guión y listo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;!DOCTYPE html>\n&#x3C;html>\n  &#x3C;head>\n    &#x3C;h1>NinjaTitle&#x3C;/h1>\n  &#x3C;/head>\n  &#x3C;body>\n      &#x3C;p>Bienvenidos a vuestro template ejs &#x3C;%- title %>&#x3C;/p>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre></div>\n<p>Ahora ya tendríamos algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-26-at-21.44.21.png\" alt=\"Html in ejs template\"><br>\nAcabamos de ver como podemos pasarle estructuras de HTML directamente a la vista, pero todavía podemos hacer más cosas interesantes. Una de las ventajas de <strong>ejs</strong> es que podemos usar código javaScript directamente en la vista, vamos a ver algunos ejemplos<br>\nEmpecemos por ver como podríamos hacer un condicional, cambiémos nuestro <strong>index.ejs</strong> por esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;!DOCTYPE html>\n&#x3C;html>\n  &#x3C;head>\n    &#x3C;h1>NinjaTitle&#x3C;/h1>\n  &#x3C;/head>\n  &#x3C;body>\n      &#x3C;p>Bienvenidos a vuestro template ejs &#x3C;%- title %>&#x3C;/p>\n&#x3C;% if (title === 'Ninjas'){ %>\n       &#x3C;p>Somos Ninjas&#x3C;/p>\n&#x3C;%}else{%>\n      &#x3C;p>Te has equivocadooooo&#x3C;/p> \n&#x3C;%}%>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre></div>\n<p>Y que no se nos olvide cambiar en nuestro <strong>index.js</strong> la línea de <strong>render</strong> por</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.render('index', { title: newTitle});\n</code></pre></div>\n<p>Solo es quitarle los <em>tags</em> HTML.<br>\nAhora vamos a probarlo, pongamos por ejemplo esto en la url<br>\n<strong><a href=\"http://localhost:3000/?title=Superman\">http://localhost:3000/?title=Superman</a></strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.12.54.png\" alt=\"Wrong Title\"><br>\nVemos como al no cumplir la condición sale la segunda opción, ahora probemos con nuestro <em>title=Ninjas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.15.15.png\" alt=\"Ninjas Title\"><br>\nPor último vamos a probar a trabajar con un <em>array</em> de elementos. Creemos lo primero nuestro objeto array en <strong>index.js</strong>, cambiando el ya conocido <strong>res.render</strong> por</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.render('index', { \n    title: newTitle,\n    superHeros: [{name: 'Dr. Manhattan'},{name: 'Superman'},{name: 'El Comendiante'}]\n  });\n</code></pre></div>\n<p>Ya tenemos nuestro array de elementos, ahora hagamos que la vista trabaje con ellos, en <strong>index.ejs</strong> añadimos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;!DOCTYPE html>\n&#x3C;html>\n  &#x3C;head>\n    &#x3C;h1>NinjaTitle&#x3C;/h1>\n  &#x3C;/head>\n  &#x3C;body>\n      &#x3C;p>Bienvenidos a vuestro template ejs &#x3C;%- title %>&#x3C;/p>\n&#x3C;% if (title === 'Ninjas'){ %>\n       &#x3C;p>Somos Ninjas&#x3C;/p>\n       \n       &#x3C;% superHeros.forEach(function(hero){ %>\n        \n         &#x3C;p>&#x3C;%= hero.name %>&#x3C;/p>\n        \n       &#x3C;%})%>\n       \n&#x3C;%}else{%>\n      &#x3C;p>Te has equivocadooooo&#x3C;/p> \n&#x3C;%}%>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre></div>\n<p>Si os fijáis hemos recorrido directamente el objeto <strong>superHeros</strong> y hemos mostrado la propiedad <strong>name</strong> de cada uno. Veamos lo que pasa cuando usamos <strong>title=Ninjas</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.27.49.png\" alt=\"Array in ejs\"><br>\nVoilá, como véis es relativamente sencillo utilizar templates ejs, esto ha sido solo una pequeña muestra de como podemos ir trabajando con ellos pero las posibilidades son infinitas (y también recordar que tenemos multitud de engines distintos).</p>\n<p>Hasta aquí lo que quería comentar sobre los templates, en los siguientes post veremos como gestionar autenticación en nuestra API, uso de Promesas....y varias cosas más, nos veeemossss</p>\n<p>Un abrazooorrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora le toca el turno a las vistas o templates, aunque realmente este tema es muy amplio porque "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"express"}]},{"type":"text","value":" admite multitud de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"engines"}]},{"type":"text","value":" de templates distintos. En la "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/expressjs/express/wiki#template-engines"},"children":[{"type":"text","value":"documentación oficial"}]},{"type":"text","value":" tenéis todos los que soporta y como se usan, veremos ejemplos con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":" porque es muy típico pero realmente podéis usar el que queráis."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor para servirlas al cliente ya que aumentas la carga de trabajo del servidor, prefiero usar Node+Express como API Rest y para las vistas usar directamente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"AngularJS"}]},{"type":"text","value":", "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ReactJS"}]},{"type":"text","value":" o similar pero al final depende un poco del proyecto o aplicación que estemos realizando, si es una página simple, casi como las que hemos visto de ejemplo, usamos los templates y ale a correr."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno después de quejarme un poco vamos a continuar....como he comentado trabajaremos un poco con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":" y para ello lo primero que tenemos que hacer es instalar el engine."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install ejs --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Recordad usamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"--save"}]},{"type":"text","value":" para que al instalar el módulo lo indique también en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" y poder llevar control de versiones (y ya de paso si movemos la app que lo instale directamente)"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAntes de continuar, os cuento, nosotros vamos a modificar nuestro proyecto de express actual para cambiar el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"engine"}]},{"type":"text","value":" pero si de primeras ya sabéis que váis a usar un engine en concreto, si recordáis se lo podíamos indicar a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"express_generator"}]},{"type":"text","value":" para que configure él directamente, si probáis el comando:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"express -h\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"veréis las opciones que tenemos"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.03.31.png","alt":"Express help"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAún así no penséis que cambiar de uno a otro es muy difícil solo tenemos que saber que caracteriza a cada uno, o más bien como se compone cada uno. En el caso de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":" es que realmente tu realizas la composición sobre código HTML, supongo que es una de las claves de su aceptación, básicamente es lo mismo que ya se estaba haciendo desde hace años pero con vitaminas."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"El primer cambio que haremos una vez instalado es cambiar el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"engine"}]},{"type":"text","value":" en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":", para ello vamos a cambiar la línea"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.set('view engine', 'jade');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"por esta otra (solo cambiando jade....superdifícil)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.set('view engine', 'ejs');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos el primer paso, lo siguiente que haremos será cambiar la vista "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index"}]},{"type":"text","value":" por ejemplo(solo cambiaremos una para que veáis de que va). Priemo eliminamos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.jade"}]},{"type":"text","value":" de la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"views"}]},{"type":"text","value":" y creamos otro que sea "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.ejs"}]},{"type":"text","value":". Una vez creado vamos a empezar por un código simple de HTML(mu feo lo sé es para probar solo)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n</html>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos muestra ya lo siguiente"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.43.35.png","alt":"Ejs Template Index change"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nYa funciona. Ahora vamos a prepararlo para que use la variable "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"title"}]},{"type":"text","value":" que le pasabamos desde el middleware."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%= title %></p>\n  </body>\n</html>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis la variable esta puesta directamente entre "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"<%= %>"}]},{"type":"text","value":", fácil ¿verdad?. Ahora vamos a probarlo, recordar que teníamos configurado el middleware para que usara los datos recibidos de la "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"query string"}]},{"type":"text","value":", por lo que la URL debería ser algo similar a"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/?title=Ninjas\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y nos debería mostrar algo similar a"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.50.14.png","alt":"Ejs template title done"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVoilá supersencillo. Ahora veamos alguna cosa más que podemos hacer con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn el ejemplo hemos usado <%= %> para trabajar con variables, pero claro si queremos poner código HTML como variable, ¿funcionaría? Veamos que pasa."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nCambiamos la variable title que le mandamos a la vista, en nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":" cambias "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.render"}]},{"type":"text","value":" por"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.render('index', { title: '<h2>' + newTitle + '</h2>' });\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y ahora veamos el resultado"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/html_tags.PNG","alt":"html_tags"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nUps!!! nos aparace todo literal, eso es porque con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"<%= %>"}]},{"type":"text","value":" básicamente conseguimos que nos transforme todo a literal(en este caso un string), pero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":" está preparado para esto, solo tenemos que cambiar los tags en nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.ejs"}]},{"type":"text","value":", básicamente cambiamos el igual por un guión y listo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n  </body>\n</html>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora ya tendríamos algo similar a esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-26-at-21.44.21.png","alt":"Html in ejs template"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAcabamos de ver como podemos pasarle estructuras de HTML directamente a la vista, pero todavía podemos hacer más cosas interesantes. Una de las ventajas de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ejs"}]},{"type":"text","value":" es que podemos usar código javaScript directamente en la vista, vamos a ver algunos ejemplos"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEmpecemos por ver como podríamos hacer un condicional, cambiémos nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.ejs"}]},{"type":"text","value":" por esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n<% if (title === 'Ninjas'){ %>\n       <p>Somos Ninjas</p>\n<%}else{%>\n      <p>Te has equivocadooooo</p> \n<%}%>\n  </body>\n</html>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y que no se nos olvide cambiar en nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":" la línea de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"render"}]},{"type":"text","value":" por"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.render('index', { title: newTitle});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Solo es quitarle los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"tags"}]},{"type":"text","value":" HTML."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora vamos a probarlo, pongamos por ejemplo esto en la url"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"http://localhost:3000/?title=Superman"},"children":[{"type":"text","value":"http://localhost:3000/?title=Superman"}]}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.12.54.png","alt":"Wrong Title"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos como al no cumplir la condición sale la segunda opción, ahora probemos con nuestro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"title=Ninjas"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.15.15.png","alt":"Ninjas Title"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último vamos a probar a trabajar con un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"array"}]},{"type":"text","value":" de elementos. Creemos lo primero nuestro objeto array en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":", cambiando el ya conocido "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res.render"}]},{"type":"text","value":" por"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.render('index', { \n    title: newTitle,\n    superHeros: [{name: 'Dr. Manhattan'},{name: 'Superman'},{name: 'El Comendiante'}]\n  });\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos nuestro array de elementos, ahora hagamos que la vista trabaje con ellos, en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.ejs"}]},{"type":"text","value":" añadimos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<!DOCTYPE html>\n<html>\n  <head>\n    <h1>NinjaTitle</h1>\n  </head>\n  <body>\n      <p>Bienvenidos a vuestro template ejs <%- title %></p>\n<% if (title === 'Ninjas'){ %>\n       <p>Somos Ninjas</p>\n       \n       <% superHeros.forEach(function(hero){ %>\n        \n         <p><%= hero.name %></p>\n        \n       <%})%>\n       \n<%}else{%>\n      <p>Te has equivocadooooo</p> \n<%}%>\n  </body>\n</html>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis hemos recorrido directamente el objeto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"superHeros"}]},{"type":"text","value":" y hemos mostrado la propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"name"}]},{"type":"text","value":" de cada uno. Veamos lo que pasa cuando usamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"title=Ninjas"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.27.49.png","alt":"Array in ejs"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVoilá, como véis es relativamente sencillo utilizar templates ejs, esto ha sido solo una pequeña muestra de como podemos ir trabajando con ellos pero las posibilidades son infinitas (y también recordar que tenemos multitud de engines distintos)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hasta aquí lo que quería comentar sobre los templates, en los siguientes post veremos como gestionar autenticación en nuestra API, uso de Promesas....y varias cosas más, nos veeemossss"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un abrazooorrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[]},"featureImageSharp":{"base":"nodebaner-4-1.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4-1.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-4-1.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-4-1.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-4-1.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-4-1.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-4-1.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-4-1.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-4-1.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-4-1.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-4-1.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-4-1.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-4-1.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-4-1.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-4-1.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-4-1.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"next":{"id":"Ghost__Post__5a338158333e0f134c248f34","title":"Don't stop the party: Node JS(VIII) Express generator","slug":"dont-stop-the-party-node-js-vii-mvc-y-express","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-4.jpg","excerpt":"En el post anterior vimos como es el trabajo básico con express, creamos una API\nque respondía a un método get y nos devolvía un mensaje, con eso más o menos ya\ntendríamos que tener una idea de como es el trabajo con node usando otro tipo de\nmétodos (get,post,put,..)(con la ayuda de la documentación oficial\n[http://expressjs.com/es/4x/api.html]), más adelante haremos ejemplos mucho más\ncomplejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web\nToken para autenticar usuarios....","custom_excerpt":null,"visibility":"public","created_at_pretty":"16 Sep 2017","published_at_pretty":"28 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-16T19:32:34.000+02:00","published_at":"2017-09-28T10:26:00.000+02:00","updated_at":"2018-01-22T09:43:18.000+01:00","meta_title":null,"meta_description":"En el post anterior vimos un poco Express, en este post veremos como usar Express Generator para montar nuestra estructura básica de proyecto.","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"En el post anterior vimos como es el trabajo básico con express, creamos una API\nque respondía a un método get y nos devolvía un mensaje, con eso más o menos ya\ntendríamos que tener una idea de como es el trabajo con node usando otro tipo de\nmétodos (get,post,put,..)(con la ayuda de la documentación oficial\n[http://expressjs.com/es/4x/api.html]), más adelante haremos ejemplos mucho más\ncomplejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web\nToken para autenticar usuarios...... pero antes de todo esto vamos a ver como se\nestructuraría un proyecto de Node+express y para ello nos vamos a valer de una\nherramienta llamada Express Generator que básicamente nos crea toda la\nestructura de carpetas y ficheros básicos que debería tener cualquier proyecto\nde este tipo.\nLo primero de todo es instalarla con npm de manera global ya que no nos serviría\ncomo proyecto si no tenemos proyecto......\n\nnpm install express-generator -g\n\n\nUna vez instalada podemos hacer\n\nexpress -h\n\n\nY vemos que opciones tenemos a la hora de crear nuestro proyecto\n\nComo véis podemos indicarle varios engines html(precesadores de html que\ngestionan la parte dinámica como datos de base de datos, etc, en el servidor y\nlo envían ya construido al cliente), css (más o menos mismo concepto) o si\nqueremos añadir un fichero gitignore a nuestro proyecto directamente(muy útil\npor cierto). Cada uno debería elegir las opciones con las que se sienta más\ncómodo (o las que nos obligue el proyecto).\nPara generar un proyecto nuevo es suficiente con escribir express\nnombreDeProyecto\n\nexpress ninja_project\n\n\nEsto nos creará algunas carpetas con varios ficheros en ellas\n\nLo primero miremos el fichero package.json para ver que nos ha configurado por\ndefecto. Tendríamos que tener algo similar a esto\n\n{\n  \"name\": \"ninja-project\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node ./bin/www\"\n  },\n  \"dependencies\": {\n    \"body-parser\": \"~1.17.1\",\n    \"cookie-parser\": \"~1.4.3\",\n    \"debug\": \"~2.6.3\",\n    \"express\": \"~4.15.2\",\n    \"jade\": \"~1.11.0\",\n    \"morgan\": \"~1.8.1\",\n    \"serve-favicon\": \"~2.4.2\"\n  }\n}\n\n\nLo primero destacable que vemos es que nos ha creado un script llamado start \ndonde tiene toda la pinta que es el punto de entrada de nuestra aplicación. A\ncontinuación vemos como nos ha seleccionado varias dependecias para ser\ninstaladas, por ejemplo body-parser [https://www.npmjs.com/package/body-parser] \nherramienta para parsear los elementos del body de una petición (se encontraría\ndentro del request que vimos en el post anterior, exactamente en request.body) o \nmorgan el logger que ya vimos.\nA continuación tendríamos que instalar las dependencias de nuestro proyecto, por\nlo que dentro de la carpeta ninja_project ejecutamos\n\nnpm install\n\n\nEsto nos instala, todas las dependencias que tenemos en nuestro package.json y\ntambién las dependencias de estas, básicamente un montón de dependencias\njejejeje\n\nCon esto ya tendríamos todo listo para empezar, pero antes veamos un poco que es\nlo que nos ha configurado, primero de todo nos vamos al fichero por el que\ncomenzaría nuestra aplicación bin/www.\nEn general supongo que al verlo os haréis una idea, resumiendo mucho este\nfichero es el que nos configura la aplicación para que escuche en algún puerto,\nveamos un poco como lo hace.\n\nLo primero a tener en cuenta es que requiere app, es decir, el fichero app.js de\nla raíz del proyecto. Este fichero básicamente es la instancia de express con\nalgunas de sus configuraciones como son los módulos que va necesitar\n\nvar express = require('express');\nvar path = require('path');\nvar favicon = require('serve-favicon');\nvar logger = require('morgan');\nvar cookieParser = require('cookie-parser');\nvar bodyParser = require('body-parser');\n\nvar index = require('./routes/index');\nvar users = require('./routes/users');\n\n\ndonde se encuentran las vistas y cuál es el engine para procesar y mostrar estas\nvistas como html\n\napp.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'jade');\n\n\nnivel de logs, la instanciación o configuración de algunos módulos y donde están\nlos ficheros estáticos(en general siempre estan en una carpeta public o similar)\n\napp.use(logger('dev'));\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(express.static(path.join(__dirname, 'public')));\n\n\nviene con escuchas de tipo get (son los requires de la carpeta routes, mirarlos\ny veréis como son de sencillitos, más abajo los vemos)\n\napp.use('/', index);\napp.use('/users', users);\n\n\nNos configura también una respuesta 404, es decir, página no encontrada si\nrecibe un path url que no existe y se lo pasa a la ultima parte que es el error\nhandler\n\n// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n\n\n\nComo véis una configuración bastante sencilla por parte del fichero app.js,\ncontinuemos con nuestro bin/www.\nLo siguiente requiere el módulo de debug y de http con la intención de\nconfigurar el puerto de escucha de la aplicación(con la posibilidad de usar una\nvariable de entorno con nombre PORT para usar otra que no sea el de por defecto)\ny por último lo inicia.\n\n/**\n * Get port from environment and store in Express.\n */\n\nvar port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n/**\n * Listen on provided port, on all network interfaces.\n */\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\n\n\nTenemos alguna cosa más pero creo que eso es lo más importante, el resto del\nfichero supongo que se entiende (más o menos).\nVeamos ahora lo que tenemos en routes, miremos por ejemplo index.js\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Express' });\n});\n\nmodule.exports = router;\n\n\nTiene instanciado la propiedad router, a la que le configura un manejador en la \nurl raíz que lo que que hará como respuesta(el parámetro res del callback) es\nrendear la vista index pasándole el título Express.\nVeamos la vista index.jade (si lo habéis dejado por defecto será jade si no\naparecerá otra cosa)\n\nextends layout\n\nblock content\n  h1= title\n  p Welcome to #{title}\n\n\nEstp es una plantilla de jade que esta extendiendo de otra que es layout,jade \npero a nosotros realmente nos interesa el title, este title es el parámetro que\nle enviamos desde el index.js, vamos a cambiarlo y al final veremos como queda,\nen el index.js ponemos esto por ejemplo (podéis poner lo que queráis)\n\nvar express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Ninja Project' });\n});\n\nmodule.exports = router;\n\n\nComo véis es bastante sencillo lo que nos ha configurado express, ahora mismo ya\npodemos arrancar la aplicación con el script que hemos visto que tenia el \npackage.json, es decir, con npm start y ya tendríamos nuestra app con express\nlevantada, en el puerto 3000(si no hemos usado la variable de entorno para\ncambiarlo claro está).\nUna vez ejecutada si accedemos con un navegador a localhost:3000 veríamos en el\nnavegador algo similar a esto\n\nY en la consola, veríamos lo que ya vimos usando el módulo morgan\n\nPor último comentar que aunque en el código lo llamen variables de entorno se\npueden elegir los parámetros directamente con comandos, veamos uno que cambia\ntodo\n\nDEBUG=nombreApp:* PORT=3500 NODE_ENV=production npm start\n\n\nOs cuento paso a paso:\n\n * DEBUG=nombreApp:* Esto solo es para sacar más información en los logs, si\n   ponemos nombreApp:* nos sacaría información de debug de todos los módulos\n   pero podríamos indicarle un módulo específico para sacar solo información de\n   el.\n * PORT=3500: Como os podéis imaginar esto nos cambiar el puerto de ejecución\n   del 3000 que viene por defecto, al que nosotros le pongamos.\n * NODE_ENV=production: Por defecto node se ejecuta en modo desarrollo,\n   básicamente provee de información más específica en los logs, ponerlo en\n   producción simplemente es por evitar que en los logs aparezca información\n   sensible en cuanto a datos o diseño de nuestra infraestructura u\n   organización.\n\nPara evitar tener que poner siempre parámetros largos recordar que podemos crear\nnuestros propios scripts por lo que podríamos crearnos otro que sea\n\n\"scripts\": {\n    \"production\": \"DEBUG=nombreApp:* PORT=3500 NODE_ENV=production node ./bin/www\"\n  },\n\n\nY voilá ya tendríamos nuestro script de npm en producción, con debug y con un\npuerto custom.\nCreo que para un post tenemos suficiente jejejeje, en el siguiente vamos a ver\nun poco más sobre las rutas, que podemos hacer con ellas, que significado\nimplícito tiene cada tipo....y algunas cosas más ;)\n\nUn abrazooooorrr","html":"<!--kg-card-begin: markdown--><p>En el post anterior vimos como es el trabajo básico con <strong>express</strong>, creamos una API que respondía a un método <strong>get</strong> y nos devolvía un mensaje, con eso más o menos ya tendríamos que tener una idea de como es el trabajo con node usando otro tipo de métodos (get,post,put,..)(con la ayuda de la <a href=\"http://expressjs.com/es/4x/api.html\">documentación oficial</a>), más adelante haremos ejemplos mucho más complejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web Token para autenticar usuarios...... pero antes de todo esto vamos a ver como se estructuraría un proyecto de <strong>Node+express</strong> y para ello nos vamos a valer de una herramienta llamada <strong>Express Generator</strong> que básicamente nos crea toda la estructura de carpetas y ficheros básicos que debería tener cualquier proyecto de este tipo.<br>\nLo primero de todo es instalarla con <strong>npm</strong> de manera global ya que no nos serviría como proyecto si no tenemos proyecto......</p>\n<pre><code>npm install express-generator -g\n</code></pre>\n<p>Una vez instalada podemos hacer</p>\n<pre><code>express -h\n</code></pre>\n<p>Y vemos que opciones tenemos a la hora de crear nuestro proyecto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.32.14.png\" alt=\"express-generator help\"><br>\nComo véis podemos indicarle varios <strong>engines</strong> html(precesadores de html que gestionan la parte dinámica como datos de base de datos, etc, en el servidor y lo envían ya construido al cliente), css (más o menos mismo concepto) o si queremos añadir un fichero <strong>gitignore</strong> a nuestro proyecto directamente(muy útil por cierto). Cada uno debería elegir las opciones con las que se sienta más cómodo (o las que nos obligue el proyecto).<br>\nPara generar un proyecto nuevo es suficiente con escribir <strong>express nombreDeProyecto</strong></p>\n<pre><code>express ninja_project\n</code></pre>\n<p>Esto nos creará algunas carpetas con varios ficheros en ellas<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.39.33.png\" alt=\"Demo Project\"><br>\nLo primero miremos el fichero <strong>package.json</strong> para ver que nos ha configurado por defecto. Tendríamos que tener algo similar a esto</p>\n<pre><code>{\n  &quot;name&quot;: &quot;ninja-project&quot;,\n  &quot;version&quot;: &quot;0.0.0&quot;,\n  &quot;private&quot;: true,\n  &quot;scripts&quot;: {\n    &quot;start&quot;: &quot;node ./bin/www&quot;\n  },\n  &quot;dependencies&quot;: {\n    &quot;body-parser&quot;: &quot;~1.17.1&quot;,\n    &quot;cookie-parser&quot;: &quot;~1.4.3&quot;,\n    &quot;debug&quot;: &quot;~2.6.3&quot;,\n    &quot;express&quot;: &quot;~4.15.2&quot;,\n    &quot;jade&quot;: &quot;~1.11.0&quot;,\n    &quot;morgan&quot;: &quot;~1.8.1&quot;,\n    &quot;serve-favicon&quot;: &quot;~2.4.2&quot;\n  }\n}\n</code></pre>\n<p>Lo primero destacable que vemos es que nos ha creado un <strong>script</strong> llamado <strong>start</strong> donde tiene toda la pinta que es el punto de entrada de nuestra aplicación. A continuación vemos como nos ha seleccionado varias dependecias para ser instaladas, por ejemplo <a href=\"https://www.npmjs.com/package/body-parser\"><strong>body-parser</strong></a> herramienta para parsear los elementos del body de una petición (se encontraría dentro del <strong>request</strong> que vimos en el post anterior, exactamente en <strong>request.body</strong>) o <strong>morgan</strong> el logger que ya vimos.<br>\nA continuación tendríamos que instalar las dependencias de nuestro proyecto, por lo que dentro de la carpeta <strong>ninja_project</strong> ejecutamos</p>\n<pre><code>npm install\n</code></pre>\n<p>Esto nos instala, todas las dependencias que tenemos en nuestro <strong>package.json</strong> y también las dependencias de estas, básicamente un montón de dependencias jejejeje<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.51.54.png\" alt=\"npm install\"><br>\nCon esto ya tendríamos todo listo para empezar, pero antes veamos un poco que es lo que nos ha configurado, primero de todo nos vamos al fichero por el que comenzaría nuestra aplicación <strong>bin/www</strong>.<br>\nEn general supongo que al verlo os haréis una idea, resumiendo mucho este fichero es el que nos configura la aplicación para que escuche en algún puerto, veamos un poco como lo hace.</p>\n<p>Lo primero a tener en cuenta es que <strong>requiere app</strong>, es decir, el fichero <strong>app.js</strong> de la raíz del proyecto. Este fichero básicamente es la instancia de express con algunas de sus configuraciones como son los módulos que va necesitar</p>\n<pre><code>var express = require('express');\nvar path = require('path');\nvar favicon = require('serve-favicon');\nvar logger = require('morgan');\nvar cookieParser = require('cookie-parser');\nvar bodyParser = require('body-parser');\n\nvar index = require('./routes/index');\nvar users = require('./routes/users');\n</code></pre>\n<p>donde se encuentran las vistas y cuál es el <strong>engine</strong> para procesar y mostrar estas vistas como html</p>\n<pre><code>app.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'jade');\n</code></pre>\n<p>nivel de logs, la instanciación o configuración de algunos módulos y donde están los ficheros estáticos(en general siempre estan en una carpeta public o similar)</p>\n<pre><code>app.use(logger('dev'));\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(express.static(path.join(__dirname, 'public')));\n</code></pre>\n<p>viene con <strong>escuchas</strong> de tipo <strong>get</strong> (son los requires de la carpeta routes, mirarlos y veréis como son de sencillitos, más abajo los vemos)</p>\n<pre><code>app.use('/', index);\napp.use('/users', users);\n</code></pre>\n<p>Nos configura también una respuesta <strong>404</strong>, es decir, página no encontrada si recibe un <strong>path url</strong> que no existe y se lo pasa a la ultima parte que es el <strong>error handler</strong></p>\n<pre><code>// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n\n</code></pre>\n<p>Como véis una configuración bastante sencilla por parte del fichero <strong>app.js</strong>, continuemos con nuestro <strong>bin/www</strong>.<br>\nLo siguiente <strong>requiere</strong> el módulo de <strong>debug</strong> y de <strong>http</strong> con la intención de configurar el puerto de escucha de la aplicación(con la posibilidad de usar una variable de entorno con nombre <strong>PORT</strong> para usar otra que no sea el de por defecto) y por último lo inicia.</p>\n<pre><code>/**\n * Get port from environment and store in Express.\n */\n\nvar port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n/**\n * Listen on provided port, on all network interfaces.\n */\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\n</code></pre>\n<p>Tenemos alguna cosa más pero creo que eso es lo más importante, el resto del fichero supongo que se entiende (más o menos).<br>\nVeamos ahora lo que tenemos en <strong>routes</strong>, miremos por ejemplo <strong>index.js</strong></p>\n<pre><code>var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Express' });\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Tiene instanciado la propiedad <strong>router</strong>, a la que le configura un manejador en la <strong>url raíz</strong> que lo que que hará como respuesta(el parámetro <strong>res</strong> del callback) es rendear la vista index pasándole el título <strong>Express</strong>.<br>\nVeamos la vista <strong>index.jade</strong> (si lo habéis dejado por defecto será jade si no aparecerá otra cosa)</p>\n<pre><code>extends layout\n\nblock content\n  h1= title\n  p Welcome to #{title}\n</code></pre>\n<p>Estp es una plantilla de <strong>jade</strong> que esta extendiendo de otra que es <strong>layout,jade</strong> pero a nosotros realmente nos interesa el <strong>title</strong>, este title es el parámetro que le enviamos desde el <strong>index.js</strong>, vamos a cambiarlo y al final veremos como queda, en el <strong>index.js</strong> ponemos esto por ejemplo (podéis poner lo que queráis)</p>\n<pre><code>var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Ninja Project' });\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Como véis es bastante sencillo lo que nos ha configurado express, ahora mismo ya podemos arrancar la aplicación con el <strong>script</strong> que hemos visto que tenia el <strong>package.json</strong>, es decir, con <strong>npm start</strong> y ya tendríamos nuestra app con express levantada, en el puerto <strong>3000</strong>(si no hemos usado la variable de entorno para cambiarlo claro está).<br>\nUna vez ejecutada si accedemos con un navegador a <strong>localhost:3000</strong> veríamos en el navegador algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-21.17.00.png\" alt=\"Express generator example\"><br>\nY en la consola, veríamos lo que ya vimos usando el módulo <strong>morgan</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-20.45.15.png\" alt=\"Express generator console log\"><br>\nPor último comentar que aunque en el código lo llamen <em>variables de entorno</em> se pueden elegir los parámetros directamente con comandos, veamos uno que cambia todo</p>\n<pre><code>DEBUG=nombreApp:* PORT=3500 NODE_ENV=production npm start\n</code></pre>\n<p>Os cuento paso a paso:</p>\n<ul>\n<li><strong>DEBUG=nombreApp:*</strong> Esto solo es para sacar más información en los logs, si ponemos nombreApp:* nos sacaría información de debug de todos los módulos pero podríamos indicarle un módulo específico para sacar solo información de el.</li>\n<li><strong>PORT=3500:</strong> Como os podéis imaginar esto nos cambiar el puerto de ejecución del 3000 que viene por defecto, al que nosotros le pongamos.</li>\n<li><strong>NODE_ENV=production:</strong> Por defecto node se ejecuta en <strong>modo desarrollo</strong>, básicamente provee de información más específica en los logs, ponerlo en producción simplemente es por evitar que en los logs aparezca información sensible en cuanto a datos o diseño de nuestra infraestructura u organización.</li>\n</ul>\n<p>Para evitar tener que poner siempre parámetros largos recordar que podemos crear nuestros propios <strong>scripts</strong> por lo que podríamos crearnos otro que sea</p>\n<pre><code>&quot;scripts&quot;: {\n    &quot;production&quot;: &quot;DEBUG=nombreApp:* PORT=3500 NODE_ENV=production node ./bin/www&quot;\n  },\n</code></pre>\n<p>Y voilá ya tendríamos nuestro script de npm en producción, con debug y con un puerto custom.<br>\nCreo que para un post tenemos suficiente jejejeje, en el siguiente vamos a ver un poco más sobre las <strong>rutas</strong>, que podemos hacer con ellas, que significado implícito tiene cada tipo....y algunas cosas más ;)</p>\n<p>Un abrazooooorrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-vii-mvc-y-express/","canonical_url":null,"uuid":"6ea2c39f-03cf-4614-816f-b0ac16605713","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59bd60326c31a60001f69f52","reading_time":6,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En el post anterior vimos como es el trabajo básico con <strong>express</strong>, creamos una API que respondía a un método <strong>get</strong> y nos devolvía un mensaje, con eso más o menos ya tendríamos que tener una idea de como es el trabajo con node usando otro tipo de métodos (get,post,put,..)(con la ayuda de la <a href=\"http://expressjs.com/es/4x/api.html\">documentación oficial</a>), más adelante haremos ejemplos mucho más complejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web Token para autenticar usuarios...... pero antes de todo esto vamos a ver como se estructuraría un proyecto de <strong>Node+express</strong> y para ello nos vamos a valer de una herramienta llamada <strong>Express Generator</strong> que básicamente nos crea toda la estructura de carpetas y ficheros básicos que debería tener cualquier proyecto de este tipo.<br>\nLo primero de todo es instalarla con <strong>npm</strong> de manera global ya que no nos serviría como proyecto si no tenemos proyecto......</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install express-generator -g\n</code></pre></div>\n<p>Una vez instalada podemos hacer</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">express -h\n</code></pre></div>\n<p>Y vemos que opciones tenemos a la hora de crear nuestro proyecto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.32.14.png\" alt=\"express-generator help\"><br>\nComo véis podemos indicarle varios <strong>engines</strong> html(precesadores de html que gestionan la parte dinámica como datos de base de datos, etc, en el servidor y lo envían ya construido al cliente), css (más o menos mismo concepto) o si queremos añadir un fichero <strong>gitignore</strong> a nuestro proyecto directamente(muy útil por cierto). Cada uno debería elegir las opciones con las que se sienta más cómodo (o las que nos obligue el proyecto).<br>\nPara generar un proyecto nuevo es suficiente con escribir <strong>express nombreDeProyecto</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">express ninja_project\n</code></pre></div>\n<p>Esto nos creará algunas carpetas con varios ficheros en ellas<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.39.33.png\" alt=\"Demo Project\"><br>\nLo primero miremos el fichero <strong>package.json</strong> para ver que nos ha configurado por defecto. Tendríamos que tener algo similar a esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"name\": \"ninja-project\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node ./bin/www\"\n  },\n  \"dependencies\": {\n    \"body-parser\": \"~1.17.1\",\n    \"cookie-parser\": \"~1.4.3\",\n    \"debug\": \"~2.6.3\",\n    \"express\": \"~4.15.2\",\n    \"jade\": \"~1.11.0\",\n    \"morgan\": \"~1.8.1\",\n    \"serve-favicon\": \"~2.4.2\"\n  }\n}\n</code></pre></div>\n<p>Lo primero destacable que vemos es que nos ha creado un <strong>script</strong> llamado <strong>start</strong> donde tiene toda la pinta que es el punto de entrada de nuestra aplicación. A continuación vemos como nos ha seleccionado varias dependecias para ser instaladas, por ejemplo <a href=\"https://www.npmjs.com/package/body-parser\"><strong>body-parser</strong></a> herramienta para parsear los elementos del body de una petición (se encontraría dentro del <strong>request</strong> que vimos en el post anterior, exactamente en <strong>request.body</strong>) o <strong>morgan</strong> el logger que ya vimos.<br>\nA continuación tendríamos que instalar las dependencias de nuestro proyecto, por lo que dentro de la carpeta <strong>ninja_project</strong> ejecutamos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install\n</code></pre></div>\n<p>Esto nos instala, todas las dependencias que tenemos en nuestro <strong>package.json</strong> y también las dependencias de estas, básicamente un montón de dependencias jejejeje<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.51.54.png\" alt=\"npm install\"><br>\nCon esto ya tendríamos todo listo para empezar, pero antes veamos un poco que es lo que nos ha configurado, primero de todo nos vamos al fichero por el que comenzaría nuestra aplicación <strong>bin/www</strong>.<br>\nEn general supongo que al verlo os haréis una idea, resumiendo mucho este fichero es el que nos configura la aplicación para que escuche en algún puerto, veamos un poco como lo hace.</p>\n<p>Lo primero a tener en cuenta es que <strong>requiere app</strong>, es decir, el fichero <strong>app.js</strong> de la raíz del proyecto. Este fichero básicamente es la instancia de express con algunas de sus configuraciones como son los módulos que va necesitar</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar path = require('path');\nvar favicon = require('serve-favicon');\nvar logger = require('morgan');\nvar cookieParser = require('cookie-parser');\nvar bodyParser = require('body-parser');\n\nvar index = require('./routes/index');\nvar users = require('./routes/users');\n</code></pre></div>\n<p>donde se encuentran las vistas y cuál es el <strong>engine</strong> para procesar y mostrar estas vistas como html</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'jade');\n</code></pre></div>\n<p>nivel de logs, la instanciación o configuración de algunos módulos y donde están los ficheros estáticos(en general siempre estan en una carpeta public o similar)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use(logger('dev'));\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(express.static(path.join(__dirname, 'public')));\n</code></pre></div>\n<p>viene con <strong>escuchas</strong> de tipo <strong>get</strong> (son los requires de la carpeta routes, mirarlos y veréis como son de sencillitos, más abajo los vemos)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/', index);\napp.use('/users', users);\n</code></pre></div>\n<p>Nos configura también una respuesta <strong>404</strong>, es decir, página no encontrada si recibe un <strong>path url</strong> que no existe y se lo pasa a la ultima parte que es el <strong>error handler</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n\n</code></pre></div>\n<p>Como véis una configuración bastante sencilla por parte del fichero <strong>app.js</strong>, continuemos con nuestro <strong>bin/www</strong>.<br>\nLo siguiente <strong>requiere</strong> el módulo de <strong>debug</strong> y de <strong>http</strong> con la intención de configurar el puerto de escucha de la aplicación(con la posibilidad de usar una variable de entorno con nombre <strong>PORT</strong> para usar otra que no sea el de por defecto) y por último lo inicia.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">/**\n * Get port from environment and store in Express.\n */\n\nvar port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n/**\n * Listen on provided port, on all network interfaces.\n */\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\n</code></pre></div>\n<p>Tenemos alguna cosa más pero creo que eso es lo más importante, el resto del fichero supongo que se entiende (más o menos).<br>\nVeamos ahora lo que tenemos en <strong>routes</strong>, miremos por ejemplo <strong>index.js</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Express' });\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Tiene instanciado la propiedad <strong>router</strong>, a la que le configura un manejador en la <strong>url raíz</strong> que lo que que hará como respuesta(el parámetro <strong>res</strong> del callback) es rendear la vista index pasándole el título <strong>Express</strong>.<br>\nVeamos la vista <strong>index.jade</strong> (si lo habéis dejado por defecto será jade si no aparecerá otra cosa)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">extends layout\n\nblock content\n  h1= title\n  p Welcome to #{title}\n</code></pre></div>\n<p>Estp es una plantilla de <strong>jade</strong> que esta extendiendo de otra que es <strong>layout,jade</strong> pero a nosotros realmente nos interesa el <strong>title</strong>, este title es el parámetro que le enviamos desde el <strong>index.js</strong>, vamos a cambiarlo y al final veremos como queda, en el <strong>index.js</strong> ponemos esto por ejemplo (podéis poner lo que queráis)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Ninja Project' });\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Como véis es bastante sencillo lo que nos ha configurado express, ahora mismo ya podemos arrancar la aplicación con el <strong>script</strong> que hemos visto que tenia el <strong>package.json</strong>, es decir, con <strong>npm start</strong> y ya tendríamos nuestra app con express levantada, en el puerto <strong>3000</strong>(si no hemos usado la variable de entorno para cambiarlo claro está).<br>\nUna vez ejecutada si accedemos con un navegador a <strong>localhost:3000</strong> veríamos en el navegador algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-21.17.00.png\" alt=\"Express generator example\"><br>\nY en la consola, veríamos lo que ya vimos usando el módulo <strong>morgan</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-20.45.15.png\" alt=\"Express generator console log\"><br>\nPor último comentar que aunque en el código lo llamen <em>variables de entorno</em> se pueden elegir los parámetros directamente con comandos, veamos uno que cambia todo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">DEBUG=nombreApp:* PORT=3500 NODE_ENV=production npm start\n</code></pre></div>\n<p>Os cuento paso a paso:</p>\n<ul>\n<li><strong>DEBUG=nombreApp:*</strong> Esto solo es para sacar más información en los logs, si ponemos nombreApp:* nos sacaría información de debug de todos los módulos pero podríamos indicarle un módulo específico para sacar solo información de el.</li>\n<li><strong>PORT=3500:</strong> Como os podéis imaginar esto nos cambiar el puerto de ejecución del 3000 que viene por defecto, al que nosotros le pongamos.</li>\n<li><strong>NODE_ENV=production:</strong> Por defecto node se ejecuta en <strong>modo desarrollo</strong>, básicamente provee de información más específica en los logs, ponerlo en producción simplemente es por evitar que en los logs aparezca información sensible en cuanto a datos o diseño de nuestra infraestructura u organización.</li>\n</ul>\n<p>Para evitar tener que poner siempre parámetros largos recordar que podemos crear nuestros propios <strong>scripts</strong> por lo que podríamos crearnos otro que sea</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">\"scripts\": {\n    \"production\": \"DEBUG=nombreApp:* PORT=3500 NODE_ENV=production node ./bin/www\"\n  },\n</code></pre></div>\n<p>Y voilá ya tendríamos nuestro script de npm en producción, con debug y con un puerto custom.<br>\nCreo que para un post tenemos suficiente jejejeje, en el siguiente vamos a ver un poco más sobre las <strong>rutas</strong>, que podemos hacer con ellas, que significado implícito tiene cada tipo....y algunas cosas más ;)</p>\n<p>Un abrazooooorrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En el post anterior vimos como es el trabajo básico con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"express"}]},{"type":"text","value":", creamos una API que respondía a un método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"get"}]},{"type":"text","value":" y nos devolvía un mensaje, con eso más o menos ya tendríamos que tener una idea de como es el trabajo con node usando otro tipo de métodos (get,post,put,..)(con la ayuda de la "},{"type":"element","tagName":"a","properties":{"href":"http://expressjs.com/es/4x/api.html"},"children":[{"type":"text","value":"documentación oficial"}]},{"type":"text","value":"), más adelante haremos ejemplos mucho más complejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web Token para autenticar usuarios...... pero antes de todo esto vamos a ver como se estructuraría un proyecto de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Node+express"}]},{"type":"text","value":" y para ello nos vamos a valer de una herramienta llamada "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Express Generator"}]},{"type":"text","value":" que básicamente nos crea toda la estructura de carpetas y ficheros básicos que debería tener cualquier proyecto de este tipo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo primero de todo es instalarla con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":" de manera global ya que no nos serviría como proyecto si no tenemos proyecto......"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install express-generator -g\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Una vez instalada podemos hacer"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"express -h\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y vemos que opciones tenemos a la hora de crear nuestro proyecto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.32.14.png","alt":"express-generator help"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo véis podemos indicarle varios "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"engines"}]},{"type":"text","value":" html(precesadores de html que gestionan la parte dinámica como datos de base de datos, etc, en el servidor y lo envían ya construido al cliente), css (más o menos mismo concepto) o si queremos añadir un fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"gitignore"}]},{"type":"text","value":" a nuestro proyecto directamente(muy útil por cierto). Cada uno debería elegir las opciones con las que se sienta más cómodo (o las que nos obligue el proyecto)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPara generar un proyecto nuevo es suficiente con escribir "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"express nombreDeProyecto"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"express ninja_project\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos creará algunas carpetas con varios ficheros en ellas"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.39.33.png","alt":"Demo Project"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo primero miremos el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" para ver que nos ha configurado por defecto. Tendríamos que tener algo similar a esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"{\n  \"name\": \"ninja-project\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node ./bin/www\"\n  },\n  \"dependencies\": {\n    \"body-parser\": \"~1.17.1\",\n    \"cookie-parser\": \"~1.4.3\",\n    \"debug\": \"~2.6.3\",\n    \"express\": \"~4.15.2\",\n    \"jade\": \"~1.11.0\",\n    \"morgan\": \"~1.8.1\",\n    \"serve-favicon\": \"~2.4.2\"\n  }\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero destacable que vemos es que nos ha creado un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"script"}]},{"type":"text","value":" llamado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"start"}]},{"type":"text","value":" donde tiene toda la pinta que es el punto de entrada de nuestra aplicación. A continuación vemos como nos ha seleccionado varias dependecias para ser instaladas, por ejemplo "},{"type":"element","tagName":"a","properties":{"href":"https://www.npmjs.com/package/body-parser"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"body-parser"}]}]},{"type":"text","value":" herramienta para parsear los elementos del body de una petición (se encontraría dentro del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"request"}]},{"type":"text","value":" que vimos en el post anterior, exactamente en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"request.body"}]},{"type":"text","value":") o "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"morgan"}]},{"type":"text","value":" el logger que ya vimos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nA continuación tendríamos que instalar las dependencias de nuestro proyecto, por lo que dentro de la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ninja_project"}]},{"type":"text","value":" ejecutamos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos instala, todas las dependencias que tenemos en nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" y también las dependencias de estas, básicamente un montón de dependencias jejejeje"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.51.54.png","alt":"npm install"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nCon esto ya tendríamos todo listo para empezar, pero antes veamos un poco que es lo que nos ha configurado, primero de todo nos vamos al fichero por el que comenzaría nuestra aplicación "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bin/www"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn general supongo que al verlo os haréis una idea, resumiendo mucho este fichero es el que nos configura la aplicación para que escuche en algún puerto, veamos un poco como lo hace."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero a tener en cuenta es que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"requiere app"}]},{"type":"text","value":", es decir, el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" de la raíz del proyecto. Este fichero básicamente es la instancia de express con algunas de sus configuraciones como son los módulos que va necesitar"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar path = require('path');\nvar favicon = require('serve-favicon');\nvar logger = require('morgan');\nvar cookieParser = require('cookie-parser');\nvar bodyParser = require('body-parser');\n\nvar index = require('./routes/index');\nvar users = require('./routes/users');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"donde se encuentran las vistas y cuál es el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"engine"}]},{"type":"text","value":" para procesar y mostrar estas vistas como html"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'jade');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"nivel de logs, la instanciación o configuración de algunos módulos y donde están los ficheros estáticos(en general siempre estan en una carpeta public o similar)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use(logger('dev'));\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(express.static(path.join(__dirname, 'public')));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"viene con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"escuchas"}]},{"type":"text","value":" de tipo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"get"}]},{"type":"text","value":" (son los requires de la carpeta routes, mirarlos y veréis como son de sencillitos, más abajo los vemos)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/', index);\napp.use('/users', users);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos configura también una respuesta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"404"}]},{"type":"text","value":", es decir, página no encontrada si recibe un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"path url"}]},{"type":"text","value":" que no existe y se lo pasa a la ultima parte que es el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"error handler"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"// catch 404 and forward to error handler\napp.use(function(req, res, next) {\n  var err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n// error handler\napp.use(function(err, req, res, next) {\n  // set locals, only providing error in development\n  res.locals.message = err.message;\n  res.locals.error = req.app.get('env') === 'development' ? err : {};\n\n  // render the error page\n  res.status(err.status || 500);\n  res.render('error');\n});\n\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis una configuración bastante sencilla por parte del fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":", continuemos con nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bin/www"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo siguiente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"requiere"}]},{"type":"text","value":" el módulo de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"debug"}]},{"type":"text","value":" y de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"http"}]},{"type":"text","value":" con la intención de configurar el puerto de escucha de la aplicación(con la posibilidad de usar una variable de entorno con nombre "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"PORT"}]},{"type":"text","value":" para usar otra que no sea el de por defecto) y por último lo inicia."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"/**\n * Get port from environment and store in Express.\n */\n\nvar port = normalizePort(process.env.PORT || '3000');\napp.set('port', port);\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n/**\n * Listen on provided port, on all network interfaces.\n */\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tenemos alguna cosa más pero creo que eso es lo más importante, el resto del fichero supongo que se entiende (más o menos)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVeamos ahora lo que tenemos en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"routes"}]},{"type":"text","value":", miremos por ejemplo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Express' });\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tiene instanciado la propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":", a la que le configura un manejador en la "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"url raíz"}]},{"type":"text","value":" que lo que que hará como respuesta(el parámetro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"res"}]},{"type":"text","value":" del callback) es rendear la vista index pasándole el título "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Express"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVeamos la vista "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.jade"}]},{"type":"text","value":" (si lo habéis dejado por defecto será jade si no aparecerá otra cosa)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"extends layout\n\nblock content\n  h1= title\n  p Welcome to #{title}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Estp es una plantilla de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"jade"}]},{"type":"text","value":" que esta extendiendo de otra que es "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"layout,jade"}]},{"type":"text","value":" pero a nosotros realmente nos interesa el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"title"}]},{"type":"text","value":", este title es el parámetro que le enviamos desde el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":", vamos a cambiarlo y al final veremos como queda, en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":" ponemos esto por ejemplo (podéis poner lo que queráis)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\n\n/* GET home page. */\nrouter.get('/', function(req, res, next) {\n  res.render('index', { title: 'Ninja Project' });\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis es bastante sencillo lo que nos ha configurado express, ahora mismo ya podemos arrancar la aplicación con el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"script"}]},{"type":"text","value":" que hemos visto que tenia el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":", es decir, con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm start"}]},{"type":"text","value":" y ya tendríamos nuestra app con express levantada, en el puerto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"3000"}]},{"type":"text","value":"(si no hemos usado la variable de entorno para cambiarlo claro está)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nUna vez ejecutada si accedemos con un navegador a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"localhost:3000"}]},{"type":"text","value":" veríamos en el navegador algo similar a esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-21.17.00.png","alt":"Express generator example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nY en la consola, veríamos lo que ya vimos usando el módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"morgan"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-18-at-20.45.15.png","alt":"Express generator console log"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último comentar que aunque en el código lo llamen "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"variables de entorno"}]},{"type":"text","value":" se pueden elegir los parámetros directamente con comandos, veamos uno que cambia todo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"DEBUG=nombreApp:* PORT=3500 NODE_ENV=production npm start\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Os cuento paso a paso:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"DEBUG=nombreApp:*"}]},{"type":"text","value":" Esto solo es para sacar más información en los logs, si ponemos nombreApp:* nos sacaría información de debug de todos los módulos pero podríamos indicarle un módulo específico para sacar solo información de el."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"PORT=3500:"}]},{"type":"text","value":" Como os podéis imaginar esto nos cambiar el puerto de ejecución del 3000 que viene por defecto, al que nosotros le pongamos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NODE_ENV=production:"}]},{"type":"text","value":" Por defecto node se ejecuta en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"modo desarrollo"}]},{"type":"text","value":", básicamente provee de información más específica en los logs, ponerlo en producción simplemente es por evitar que en los logs aparezca información sensible en cuanto a datos o diseño de nuestra infraestructura u organización."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para evitar tener que poner siempre parámetros largos recordar que podemos crear nuestros propios "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"scripts"}]},{"type":"text","value":" por lo que podríamos crearnos otro que sea"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"\"scripts\": {\n    \"production\": \"DEBUG=nombreApp:* PORT=3500 NODE_ENV=production node ./bin/www\"\n  },\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y voilá ya tendríamos nuestro script de npm en producción, con debug y con un puerto custom."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nCreo que para un post tenemos suficiente jejejeje, en el siguiente vamos a ver un poco más sobre las "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"rutas"}]},{"type":"text","value":", que podemos hacer con ellas, que significado implícito tiene cada tipo....y algunas cosas más ;)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un abrazooooorrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[]},"featureImageSharp":{"base":"nodebaner-4.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-4.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-4.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-4.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-4.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-4.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-4.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-4.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-4.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-4.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-4.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-4.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-4.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-4.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-4.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"allGhostPost":{"edges":[{"node":{"id":"Ghost__Post__5a338158333e0f134c248f3e","title":"Don't stop the party: Node JS(XIII) Cluster","slug":"dont-stop-the-party-node-js-xiii-cluster","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/nodebaner-1.jpg","excerpt":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que\nveremos con será, después de MongoDB, como usar las 2 cosas para hacer una API\ncompleta.\nAunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo\nque veremos a continuación podemos aumentar el rendimiento de nuestra aplicación\nnotablemente (eso sí, siempre dependiendo del entorno).\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más\nservicios, programas, ordenadores, se","custom_excerpt":null,"visibility":"public","created_at_pretty":"11 Oct 2017","published_at_pretty":"16 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-10-11T08:33:26.000+02:00","published_at":"2017-10-16T10:28:00.000+02:00","updated_at":"2018-01-22T09:34:26.000+01:00","meta_title":"Don't stop the party: Node JS(XIII) Cluster","meta_description":"Veremos como podemos configurar un Cluster de servicios de NodeJS para aumentar nuestro rendimiento casi exponencialmente.","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que\nveremos con será, después de MongoDB, como usar las 2 cosas para hacer una API\ncompleta.\nAunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo\nque veremos a continuación podemos aumentar el rendimiento de nuestra aplicación\nnotablemente (eso sí, siempre dependiendo del entorno).\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más\nservicios, programas, ordenadores, servidores....que funcionan como uno solo.\nBajo este concepto tendríamos varías opciones de configuración: balanceo de\ncarga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la \nWiki [https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)]\nEn nuestro caso, NodeJS, nos permite tener varios workers que trabajan por si\nsolos, para hacerlo simple es como si iniciaramos varias veces nuestra\naplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un\nproceso master que gestiona el resto y podemos pasar datos, comunicar eventos o\nlo que necesitemos entre los workers, entre los workers y el master y\nviceversa).\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que\ninicie el server para escuchar las peticiones por lo que vamosa nuestro proyecto\nde Express y dentro de la carpeta bin en el fichero www hacemos lo siguiente:\nBuscamos la linea donde tenemos el comentario Create server\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n\nY justo encima ponemos lo siguiente:\n\nconst cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n\nComo véis lo que hacemos es requerir el módulo cluster y básicamente es que si\nes el Master comprobamos cuantas CPUs tenemos y generamos un worker por cada\nuna. El numCpus lo que devuelve es un array donde cada elemento es información\nde cada CPU, yo simplemente he recorrido el array con el map y por cada elemento\nle he indicado que genere un worker. Esto se podría hacer de más formas con un \nfor normal o como queráis.\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha\niniciado un worker, justo debajo de los server.on y cerramos el else\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n\n\nBien creo que ya estamos listos para ejecutarlo, asi que ya sabéis\n\nnpm start\n\n\nY si miramos el log\n\nA mi me ha arrancado 4 workers, esto dependerá del número de CPUs de cada\nequipo.\nHablemos un poco más de como funciona un cluster en Node. En este caso\nespecífico se útiliza el método round-robin\n[https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin] para repartir la\ncarga entre los workers (lo mejor es que miréis el link que he puesto si queréis\nsaber como funciona).\n\nTango el master como los workers producen eventos a los que nos podemos \nsuscribir, al mismo estilo que hicimos con el event emitter\n[https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/] en su momento,\nlo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es\nque miréis la documentación oficial\n[https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html] que como veréis\nviene con mucho código de ejemplo para que lo entendáis mejor.\nTambién es posible que el master mande mensajes a los workers, veamoslo con un\npequeño ejemplo. Dentro del if, es decir en el master añadimos\n\n //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n\n\nY en el else donde instanciamos los workers\n\nprocess.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n\n\nNos suscribimos al evento message y devolvemos un mensaje en consola con el\nmensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje\nque hemos pasado a cada worker, y además cada vez que ejecutemos nos aparecerá\nen distinto momento ya que no sabemos cuando se instancia cada worker\n\n\n\nEsto solo es un ejemplo si repasais la documentación veréis que podéis hacer\nmultitud de cosas distintas ;)\n\nBueno y hasta aquí la parte de Cluster, como habéis visto es relativamente\nsencillo y ya podéis usarlo tranquilamente en vuestros proyectos con NodeJS.\n\nTambién (por el momento) aquí finalizamos la parte específica de Node ya lo\nsiguiente que veremos será usandolo con MongoDB para trabajar con esta base de\ndatos y crear una API Rest con un entorno más realista, así que empezaré con una\nnueva línea dedicada a MongoDB dentro de nada, espero que la parte de Node os\nhaya parecido interesante y suficiente para poder realizar vuestros propios\nproyectos.\n\nEstad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr","html":"<!--kg-card-begin: markdown--><p>Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa.<br>\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno).<br>\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la <a href=\"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)\">Wiki</a><br>\nEn nuestro caso, NodeJS, nos permite tener varios <em>workers</em> que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso <em>master</em> que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa).<br>\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el <em>server</em> para <em>escuchar</em> las peticiones por lo que vamosa nuestro proyecto de <em>Express</em> y dentro de la carpeta <strong>bin</strong> en el fichero <strong>www</strong> hacemos lo siguiente:<br>\nBuscamos la linea donde tenemos el comentario <em>Create server</em></p>\n<pre><code>/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre>\n<p>Y justo encima ponemos lo siguiente:</p>\n<pre><code>const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() =&gt; {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre>\n<p>Como véis lo que hacemos es <em>requerir</em> el módulo <strong>cluster</strong> y básicamente es que si es el <em>Master</em> comprobamos cuantas CPUs tenemos y generamos un <em>worker</em> por cada una. El <em>numCpus</em> lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un <em>worker</em>. Esto se podría hacer de más formas con un <em>for</em> normal o como queráis.<br>\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los <em>server.on</em> y cerramos el <em>else</em></p>\n<pre><code>server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n</code></pre>\n<p>Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis</p>\n<pre><code>npm start\n</code></pre>\n<p>Y si miramos el log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png\" alt=\"Workers Started\"><br>\nA mi me ha arrancado 4 <em>workers</em>, esto dependerá del número de CPUs de cada equipo.<br>\nHablemos un poco más de como funciona un cluster en <em>Node</em>. En este caso específico se útiliza el método <a href=\"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin\"><strong>round-robin</strong></a> para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona).</p>\n<p>Tango el <em>master</em> como los <em>workers</em> producen eventos a los que nos podemos <em>suscribir</em>, al mismo estilo que hicimos con el <a href=\"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/\"><em>event emitter</em></a> en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la <a href=\"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html\">documentación oficial</a> que como veréis viene con mucho código de ejemplo para que lo entendáis mejor.<br>\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del <strong>if</strong>, es decir en el <em>master</em> añadimos</p>\n<pre><code> //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(&quot;Hi ninjaWorker 2&quot;)\n    workersOnline[4].send(&quot;Hi ninjaWorker 4&quot;)\n</code></pre>\n<p>Y en el <em>else</em> donde instanciamos los <em>workers</em></p>\n<pre><code>process.on('message',(message)=&gt;{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n</code></pre>\n<p>Nos suscribimos al evento <em>message</em> y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada <em>worker</em>, y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada <em>worker</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png\" alt=\"Master send event 1\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png\" alt=\"Master send event 2\"></p>\n<p>Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)</p>\n<p>Bueno y hasta aquí la parte de <em>Cluster</em>, como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con <em>NodeJS</em>.</p>\n<p>También (por el momento) aquí finalizamos la parte específica de <strong>Node</strong> ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una <em>API Rest</em> con un entorno más realista, así que empezaré con una nueva línea dedicada a <em>MongoDB</em> dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos.</p>\n<p>Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xiii-cluster/","canonical_url":null,"uuid":"f63943af-060c-435b-8f97-b2c6f09734da","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59ddbb3658177700014ca3b2","reading_time":4,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa.<br>\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno).<br>\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la <a href=\"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)\">Wiki</a><br>\nEn nuestro caso, NodeJS, nos permite tener varios <em>workers</em> que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso <em>master</em> que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa).<br>\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el <em>server</em> para <em>escuchar</em> las peticiones por lo que vamosa nuestro proyecto de <em>Express</em> y dentro de la carpeta <strong>bin</strong> en el fichero <strong>www</strong> hacemos lo siguiente:<br>\nBuscamos la linea donde tenemos el comentario <em>Create server</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre></div>\n<p>Y justo encima ponemos lo siguiente:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre></div>\n<p>Como véis lo que hacemos es <em>requerir</em> el módulo <strong>cluster</strong> y básicamente es que si es el <em>Master</em> comprobamos cuantas CPUs tenemos y generamos un <em>worker</em> por cada una. El <em>numCpus</em> lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un <em>worker</em>. Esto se podría hacer de más formas con un <em>for</em> normal o como queráis.<br>\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los <em>server.on</em> y cerramos el <em>else</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n</code></pre></div>\n<p>Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm start\n</code></pre></div>\n<p>Y si miramos el log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png\" alt=\"Workers Started\"><br>\nA mi me ha arrancado 4 <em>workers</em>, esto dependerá del número de CPUs de cada equipo.<br>\nHablemos un poco más de como funciona un cluster en <em>Node</em>. En este caso específico se útiliza el método <a href=\"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin\"><strong>round-robin</strong></a> para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona).</p>\n<p>Tango el <em>master</em> como los <em>workers</em> producen eventos a los que nos podemos <em>suscribir</em>, al mismo estilo que hicimos con el <a href=\"/dont-stop-the-party-node-js-v/\"><em>event emitter</em></a> en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la <a href=\"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html\">documentación oficial</a> que como veréis viene con mucho código de ejemplo para que lo entendáis mejor.<br>\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del <strong>if</strong>, es decir en el <em>master</em> añadimos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"> //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n</code></pre></div>\n<p>Y en el <em>else</em> donde instanciamos los <em>workers</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n</code></pre></div>\n<p>Nos suscribimos al evento <em>message</em> y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada <em>worker</em>, y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada <em>worker</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png\" alt=\"Master send event 1\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png\" alt=\"Master send event 2\"></p>\n<p>Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)</p>\n<p>Bueno y hasta aquí la parte de <em>Cluster</em>, como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con <em>NodeJS</em>.</p>\n<p>También (por el momento) aquí finalizamos la parte específica de <strong>Node</strong> ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una <em>API Rest</em> con un entorno más realista, así que empezaré con una nueva línea dedicada a <em>MongoDB</em> dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos.</p>\n<p>Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la "},{"type":"element","tagName":"a","properties":{"href":"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)"},"children":[{"type":"text","value":"Wiki"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn nuestro caso, NodeJS, nos permite tener varios "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":" que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"server"}]},{"type":"text","value":" para "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"escuchar"}]},{"type":"text","value":" las peticiones por lo que vamosa nuestro proyecto de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Express"}]},{"type":"text","value":" y dentro de la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bin"}]},{"type":"text","value":" en el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"www"}]},{"type":"text","value":" hacemos lo siguiente:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBuscamos la linea donde tenemos el comentario "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Create server"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y justo encima ponemos lo siguiente:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis lo que hacemos es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerir"}]},{"type":"text","value":" el módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"cluster"}]},{"type":"text","value":" y básicamente es que si es el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Master"}]},{"type":"text","value":" comprobamos cuantas CPUs tenemos y generamos un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":" por cada una. El "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"numCpus"}]},{"type":"text","value":" lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":". Esto se podría hacer de más formas con un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"for"}]},{"type":"text","value":" normal o como queráis."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"server.on"}]},{"type":"text","value":" y cerramos el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"else"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm start\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y si miramos el log"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png","alt":"Workers Started"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nA mi me ha arrancado 4 "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":", esto dependerá del número de CPUs de cada equipo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nHablemos un poco más de como funciona un cluster en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":". En este caso específico se útiliza el método "},{"type":"element","tagName":"a","properties":{"href":"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"round-robin"}]}]},{"type":"text","value":" para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tango el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" como los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":" producen eventos a los que nos podemos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"suscribir"}]},{"type":"text","value":", al mismo estilo que hicimos con el "},{"type":"element","tagName":"a","properties":{"href":"/dont-stop-the-party-node-js-v/"},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"event emitter"}]}]},{"type":"text","value":" en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la "},{"type":"element","tagName":"a","properties":{"href":"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html"},"children":[{"type":"text","value":"documentación oficial"}]},{"type":"text","value":" que como veréis viene con mucho código de ejemplo para que lo entendáis mejor."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"if"}]},{"type":"text","value":", es decir en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" añadimos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":" //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"else"}]},{"type":"text","value":" donde instanciamos los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"process.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos suscribimos al evento "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"message"}]},{"type":"text","value":" y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":", y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png","alt":"Master send event 1"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png","alt":"Master send event 2"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bueno y hasta aquí la parte de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Cluster"}]},{"type":"text","value":", como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"También (por el momento) aquí finalizamos la parte específica de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":" ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"API Rest"}]},{"type":"text","value":" con un entorno más realista, así que empezaré con una nueva línea dedicada a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"MongoDB"}]},{"type":"text","value":" dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[]},"featureImageSharp":{"base":"nodebaner-1.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-1.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-1.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-1.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-1.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-1.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-1.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-1.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-1.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-1.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-1.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-1.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-1.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-1.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-1.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__5a338158333e0f134c248f38","title":"Don't stop the party: Node JS(XII) Promesas","slug":"dont-stop-the-party-node-js-xii-promesas","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/nodebaner.jpg","excerpt":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero\nrealmente son muy útiles.\n\nPromesas\nLas promesas, si no estoy mal, se añadieron oficialmente en JS a partir de\nES6...y por resumir un poco, son como callbacks de finalización pero en bonito,\nexplicome....cuando necesitamos encadenar métodos que continenen callbacks\npodemos terminar con un código de este estilo\n\n\nRealmente es raro que nuestro código termine así, pero realmente esa es la\ntendencia , ¿verdad?.. bueno p","custom_excerpt":null,"visibility":"public","created_at_pretty":"3 Oct 2017","published_at_pretty":"12 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-10-03T21:00:17.000+02:00","published_at":"2017-10-12T10:10:00.000+02:00","updated_at":"2018-01-22T09:34:34.000+01:00","meta_title":"Don't stop the party: Node JS(XII) Promesas","meta_description":"Hablaremos de las Promesas que son parte de todo el stack de JavaScript y que nos serán muy útiles en nuestros desarrollos con NodeJS","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero\nrealmente son muy útiles.\n\nPromesas\nLas promesas, si no estoy mal, se añadieron oficialmente en JS a partir de\nES6...y por resumir un poco, son como callbacks de finalización pero en bonito,\nexplicome....cuando necesitamos encadenar métodos que continenen callbacks\npodemos terminar con un código de este estilo\n\n\nRealmente es raro que nuestro código termine así, pero realmente esa es la\ntendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las \npromesas es esa. Por definir concretamente:\nUna promesa es un objeto que, si todavía no ha terminado, aseguramos que se\ncompletará más adelante.\n\nSupongo que con esa frase queda más claro todavía qué es una promesa (y también\nsu nombre jeje). Las promesas tienen tres estados en su ciclo de vida:\n\n * Pendiente(pending): Como su nombre indica todavía está sin cumplir y cambiará\n   de estado en algún momento.\n * Completada correctamente(Fullfilled/resolve): Es decir, ha hecho su trabajo\n   correctamente y ha devuelto un valor.\n * Rechazada(rejected): En su proceso de ejecución ha dado algún tipo de error y\n   ha sido completada con error devolviendonos la razón.\n\nVeamos ahora como podemos crear una promesa\n\nvar prom = new Promise(function(resolve,reject){\n})\n\n\nBásicamente creamos un nuevo objeto Promise el cual tiene una función que recibe\ndos parámetros, con un nombre bastante intuitivo por cierto:\n\n * resolve: Llamaremos a resolve cuando todo haya ido bien y le pasamos el\n   resultado que recibirá la siguiente promesa o función.\n * reject: Llamaremos a reject cuando tengamos un error, al cual le pasaremos el\n   error.\n\nY, ¿como usamos esto? Bastante sencillo\n\nprom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n\n\nEsto lo que hace es ejecutar la promesa que hemos creado y a continuación (then)\nse ejecutará la función dentro del then donde resultado es el parámetro que\nhemos recibido desde la promesa con resolve. En el caso de que algo hubiera\nfallado o el resultado fuera insatisfactorio ejecutariamos reject con el error o\nla información que quisieramos, la cual capturaría el primer catch que\nencontrará la cadena de promesas. Por si no os lo habéis imaginado nosotros\npodemos poner todas las promesas y catch que queramos\n\nprom.then().then().then().catch().then().catch()\n\n\nY en el orden que las hemos escritor se irian ejecutando, y también según ese\norden el primer catch que se encontrara sería el que respondería en caso de\ntener un resultado reject.\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún catch. Vamos\na crear un método nuevo junto con el que ya teníamos que lo vamos a modificar,\nla idea es que cada promesa vaya encadenando un String hasta mostrarlo al final,\naunque en este caso lo que haremos será mostrarlo en cada paso para que se vea\nque esta haciendo.\nPrimero cambiamos nuestra función sleep\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n\n\nLe pasamos el parámetro hero y devolvemos un string. A continuación creamos otro\nmétodo que vaya encadenando\n\nfunction heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n\n\nDe momento dejamos comentada la parte de reject para ver el resultado. Como véis\nla función recibe un parámetro result (este primer parámetro sería lo que nos\ndevuelve la promesa en caso de resolve) y también un parámetro extra con el\nnombre de otro hero y luego simplemente lo juntamos todo para que lo devuelva en\n2 segundos.\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas\n\nprom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n\n\nDe paso le he metido un catch para probar el error más adelante. Fijáos que lo\nque hacemos es retornar dentro de una función anónima, que es la que recibe \nresult, la promesa resultante de nuestra función heros, si no necesitaramos \nresult no tendríamos porque meterlo dentro de otra función, bastaría solo con\nusar heros(\"New Hero\"). Bueno y ahora si lo probamos\n\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.\nPor último vamos a probar el catch para que veais como funciona, lo que haremos\nserá descomentar el código que tenía reject y ya podríamos probarlo.\n\nVemos que cuando le toca el turno a Green Latern pasa por el catch pero no se\ndetiene y continua......eso es porque tenemos que cambiar como funciona el catch \nya que solo hemos puesto un console.log para que se vea que pasa por allí, para\nhacer que se detenga podemos poner\n\ncatch((err) => {\n    throw err  \n})\n\n\nY ahora sí tendríamos un error al estilo promesas\n\n\nCon promesas tenemos también otras opciones, por ejemplo podemos pasar un array\nde promesas y cuando terminen todas pasa al then o al catch según si ha dado\nerror o no.\n\nPromise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n\n\nCon Promise.all, pasamos una array de promesas y esperamos a que terminen todas,\ntenemos también la opción de que pase al then cuando responda la primera\n\nPromise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n\n\nEste concepto es útil por ejemplo si tenemos varios servidores de base de datos,\nhacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno\ntermine ya tenemos un resultado, lo que nos permite responder lo más rápido\nposible ignorando si un servidor tiene más carga que otro.\n\nAhora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en\nun extra o forma de usarlas que, si no me equivoco, salió en ES7 y para esto es\nnecesario tener Node actualizado a la última versión o por lo menos en la 7.6\n(creo), con node -v podéis ver en que versión estáis y actualizar si lo\nnecesitáis.\n\nConcretamente vamos a hablar de async/await. Estos nuevos métodos nos ayudan un\npoco con la gestión de las promesas, y de los callbacks por supuesto. Lo que\nhacemos con await es esperar a que una función termine y parece ser que como \nbest practice(o que tiene que ser si o sí más bien) tenemos que hacer ese código\nasíncrono asi que nos han puesto async para facilitarnos esa tarea. Y como\nfunciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos\nteníamos antes.\nPartimos de esto\n\n'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n\n\nSe supone que tenemos que usar await para que el código se espere a que termine\nla promesa y meterlo todo dentro de async...pues vamos\n\nasync function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n\n\nComo véis simplemente hemos puesto await al principio de la ejecución de nuestra\npromesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos\nmetido todo dentro de una función que empieza con async. Ahora vamos a usarlo\ncomo si de una promesa normal se tratase\n\nasyncPromise().then((result) => console.log(result))\n\n\nBien ya tenemos todo, ahora vamos a ejecutarlo\n\n\nComo habréis podido comprobar nos ha aparecido el log indicando que empieza y a\nlos 2 segundos nos ha mostrado el resultado como si de una promesa normal se\ntratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks\nde finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con\nestas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el\nlímite lo ponéis vosotros de como usar esto.\n\nCreo que por el momento vamos a dejar las promesas (o lo relacionado con ellas)\naquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos\nvisto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que\nsolo me quedaría un mini-post más de extras de Node y nos pondríamos ya con\nMongoDB.\n\nNos veeeemosssss un abrazooorrrrr","html":"<!--kg-card-begin: markdown--><p>Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles.</p>\n<h3 id=\"promesas\">Promesas</h3>\n<p>Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif\" alt=\"callBack_hell\"></p>\n<p>Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las <em>promesas</em> es esa. Por definir concretamente:<br>\n<em>Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante</em>.</p>\n<p>Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las <em>promesas</em> tienen tres estados en su ciclo de vida:</p>\n<ul>\n<li><strong>Pendiente(pending)</strong>: Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento.</li>\n<li><strong>Completada correctamente(Fullfilled/resolve)</strong>: Es decir, ha hecho su trabajo correctamente y ha devuelto un valor.</li>\n<li><strong>Rechazada(rejected)</strong>: En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón.</li>\n</ul>\n<p>Veamos ahora como podemos crear una promesa</p>\n<pre><code>var prom = new Promise(function(resolve,reject){\n})\n</code></pre>\n<p>Básicamente creamos un nuevo objeto <strong>Promise</strong> el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:</p>\n<ul>\n<li><strong>resolve</strong>: Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente <em>promesa</em> o función.</li>\n<li><strong>reject</strong>: Llamaremos a <em>reject</em> cuando tengamos un error, al cual le pasaremos el error.</li>\n</ul>\n<p>Y, ¿como usamos esto? Bastante sencillo</p>\n<pre><code>prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n</code></pre>\n<p>Esto lo que hace es ejecutar la promesa que hemos creado y a continuación (<strong>then</strong>) se ejecutará la función dentro del <em>then</em> donde <strong>resultado</strong> es el parámetro que hemos recibido desde la promesa con <em>resolve</em>. En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos <em>reject</em> con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de <em>promesas</em>. Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos</p>\n<pre><code>prom.then().then().then().catch().then().catch()\n</code></pre>\n<p>Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado <em>reject</em>.<br>\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún <em>catch</em>. Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo.<br>\nPrimero cambiamos nuestra función <em>sleep</em></p>\n<pre><code>//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) =&gt; {\n        setTimeout(() =&gt; {\n            resolve(&quot;La liga de la justicia: &quot; + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, &quot;Superman&quot;);\n</code></pre>\n<p>Le pasamos el parámetro <em>hero</em> y devolvemos un string. A continuación creamos otro método que vaya encadenando</p>\n<pre><code>function heros(result, hero){\n    \n    return new Promise((resolve,reject) =&gt; {\n\n        /*if (hero === &quot;Green Latern&quot;){\n           reject(&quot;No aparece esta vez&quot;)\n        }*/\n\n        console.log(result)\n        setTimeout(()=&gt; {  \n             resolve(result + &quot; &quot; + hero)\n        },2000)\n     })\n}\n</code></pre>\n<p>De momento dejamos comentada la parte de <em>reject</em> para ver el resultado. Como véis la función recibe un parámetro <em>result</em> (este primer parámetro sería lo que nos devuelve la promesa en caso de <em>resolve</em>) y también un parámetro extra con el nombre de otro <em>hero</em> y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos.<br>\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas</p>\n<pre><code>prom\n.then((result) =&gt; {\n    return heros(result, &quot;Batman&quot;)\n})\n.then((result) =&gt; {\n    return heros(result, &quot;Green Latern&quot;) \n})\n.then((result) =&gt; {\n    return heros(result, &quot;Wonder Woman&quot;)\n})\n.catch((err) =&gt; {\n    console.log(err)\n})\n.then((result) =&gt; {\n    return heros(result, &quot;Aquaman&quot;)\n})\n.then((result)=&gt; { \n    console.log(result)\n})\n</code></pre>\n<p>De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe <em>result</em>, la promesa resultante de nuestra función <em>heros</em>, si no necesitaramos <em>result</em> no tendríamos porque meterlo dentro de otra función, bastaría solo con usar <em>heros(&quot;New Hero&quot;)</em>. Bueno y ahora si lo probamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png\" alt=\"Example Multiple promises\"><br>\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.<br>\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png\" alt=\"Example Catch without return\"><br>\nVemos que cuando le toca el turno a <em>Green Latern</em> pasa por el <em>catch</em> pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el <em>catch</em> ya que solo hemos puesto un <em>console.log</em> para que se vea que pasa por allí, para hacer que se detenga podemos poner</p>\n<pre><code>catch((err) =&gt; {\n    throw err  \n})\n</code></pre>\n<p>Y ahora sí tendríamos un error al <em>estilo promesas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png\" alt=\"Promises error\"></p>\n<p>Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al <em>then</em> o al <em>catch</em> según si ha dado error o no.</p>\n<pre><code>Promise.all(arrayPromises)\n    .then((result) =&gt;{console.log(result)})\n    .catch((error){})\n</code></pre>\n<p>Con <em>Promise.all</em>, pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al <em>then</em> cuando responda la primera</p>\n<pre><code>Promise.race([arrayPromises])\n    .then((result) =&gt; { console.log(&quot;La más rápida ha sido&quot; + result)})\n</code></pre>\n<p>Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro.</p>\n<p>Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y <strong>para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)</strong>, con <strong>node -v</strong> podéis ver en que versión estáis y actualizar si lo necesitáis.</p>\n<p>Concretamente vamos a hablar de <strong>async/await</strong>. Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con <strong>await</strong> es esperar a que una función termine y parece ser que como <em>best practice</em>(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto <strong>async</strong> para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes.<br>\nPartimos de esto</p>\n<pre><code>'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) =&gt; {\n        setTimeout(() =&gt; {\n            resolve(&quot;La liga de la justicia: &quot; + hero)\n            \n        }, ms);\n    });\n}\n</code></pre>\n<p>Se supone que tenemos que usar <em>await</em> para que el código se espere a que termine la promesa y meterlo todo dentro de <em>async</em>...pues vamos</p>\n<pre><code>async function asyncPromise(){\n    console.log(&quot;Empezamos a contar&quot;)\n    return await sleep(2000,&quot;Superman&quot;)\n}\n</code></pre>\n<p>Como véis simplemente hemos puesto <em>await</em> al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con <em>async</em>. Ahora vamos a usarlo como si de una promesa normal se tratase</p>\n<pre><code>asyncPromise().then((result) =&gt; console.log(result))\n</code></pre>\n<p>Bien ya tenemos todo, ahora vamos a ejecutarlo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png\" alt=\"Async Await example\"></p>\n<p>Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones &quot;nuevas&quot; de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto.</p>\n<p>Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB.</p>\n<p>Nos veeeemosssss un abrazooorrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xii-promesas/","canonical_url":null,"uuid":"df54bc2b-2b01-4415-a567-2b5d30f1f162","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59d3de4158177700014ca384","reading_time":6,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles.</p>\n<h3 id=\"promesas\">Promesas</h3>\n<p>Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif\" alt=\"callBack_hell\"></p>\n<p>Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las <em>promesas</em> es esa. Por definir concretamente:<br>\n<em>Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante</em>.</p>\n<p>Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las <em>promesas</em> tienen tres estados en su ciclo de vida:</p>\n<ul>\n<li><strong>Pendiente(pending)</strong>: Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento.</li>\n<li><strong>Completada correctamente(Fullfilled/resolve)</strong>: Es decir, ha hecho su trabajo correctamente y ha devuelto un valor.</li>\n<li><strong>Rechazada(rejected)</strong>: En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón.</li>\n</ul>\n<p>Veamos ahora como podemos crear una promesa</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var prom = new Promise(function(resolve,reject){\n})\n</code></pre></div>\n<p>Básicamente creamos un nuevo objeto <strong>Promise</strong> el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:</p>\n<ul>\n<li><strong>resolve</strong>: Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente <em>promesa</em> o función.</li>\n<li><strong>reject</strong>: Llamaremos a <em>reject</em> cuando tengamos un error, al cual le pasaremos el error.</li>\n</ul>\n<p>Y, ¿como usamos esto? Bastante sencillo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n</code></pre></div>\n<p>Esto lo que hace es ejecutar la promesa que hemos creado y a continuación (<strong>then</strong>) se ejecutará la función dentro del <em>then</em> donde <strong>resultado</strong> es el parámetro que hemos recibido desde la promesa con <em>resolve</em>. En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos <em>reject</em> con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de <em>promesas</em>. Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom.then().then().then().catch().then().catch()\n</code></pre></div>\n<p>Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado <em>reject</em>.<br>\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún <em>catch</em>. Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo.<br>\nPrimero cambiamos nuestra función <em>sleep</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n</code></pre></div>\n<p>Le pasamos el parámetro <em>hero</em> y devolvemos un string. A continuación creamos otro método que vaya encadenando</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n</code></pre></div>\n<p>De momento dejamos comentada la parte de <em>reject</em> para ver el resultado. Como véis la función recibe un parámetro <em>result</em> (este primer parámetro sería lo que nos devuelve la promesa en caso de <em>resolve</em>) y también un parámetro extra con el nombre de otro <em>hero</em> y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos.<br>\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n</code></pre></div>\n<p>De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe <em>result</em>, la promesa resultante de nuestra función <em>heros</em>, si no necesitaramos <em>result</em> no tendríamos porque meterlo dentro de otra función, bastaría solo con usar <em>heros(\"New Hero\")</em>. Bueno y ahora si lo probamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png\" alt=\"Example Multiple promises\"><br>\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.<br>\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png\" alt=\"Example Catch without return\"><br>\nVemos que cuando le toca el turno a <em>Green Latern</em> pasa por el <em>catch</em> pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el <em>catch</em> ya que solo hemos puesto un <em>console.log</em> para que se vea que pasa por allí, para hacer que se detenga podemos poner</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">catch((err) => {\n    throw err  \n})\n</code></pre></div>\n<p>Y ahora sí tendríamos un error al <em>estilo promesas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png\" alt=\"Promises error\"></p>\n<p>Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al <em>then</em> o al <em>catch</em> según si ha dado error o no.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Promise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n</code></pre></div>\n<p>Con <em>Promise.all</em>, pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al <em>then</em> cuando responda la primera</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Promise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n</code></pre></div>\n<p>Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro.</p>\n<p>Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y <strong>para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)</strong>, con <strong>node -v</strong> podéis ver en que versión estáis y actualizar si lo necesitáis.</p>\n<p>Concretamente vamos a hablar de <strong>async/await</strong>. Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con <strong>await</strong> es esperar a que una función termine y parece ser que como <em>best practice</em>(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto <strong>async</strong> para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes.<br>\nPartimos de esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n</code></pre></div>\n<p>Se supone que tenemos que usar <em>await</em> para que el código se espere a que termine la promesa y meterlo todo dentro de <em>async</em>...pues vamos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">async function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n</code></pre></div>\n<p>Como véis simplemente hemos puesto <em>await</em> al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con <em>async</em>. Ahora vamos a usarlo como si de una promesa normal se tratase</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">asyncPromise().then((result) => console.log(result))\n</code></pre></div>\n<p>Bien ya tenemos todo, ahora vamos a ejecutarlo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png\" alt=\"Async Await example\"></p>\n<p>Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto.</p>\n<p>Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB.</p>\n<p>Nos veeeemosssss un abrazooorrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"promesas"},"children":[{"type":"text","value":"Promesas"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif","alt":"callBack_hell"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":" es esa. Por definir concretamente:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":" tienen tres estados en su ciclo de vida:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Pendiente(pending)"}]},{"type":"text","value":": Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Completada correctamente(Fullfilled/resolve)"}]},{"type":"text","value":": Es decir, ha hecho su trabajo correctamente y ha devuelto un valor."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Rechazada(rejected)"}]},{"type":"text","value":": En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos ahora como podemos crear una promesa"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var prom = new Promise(function(resolve,reject){\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Básicamente creamos un nuevo objeto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Promise"}]},{"type":"text","value":" el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":": Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesa"}]},{"type":"text","value":" o función."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":": Llamaremos a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" cuando tengamos un error, al cual le pasaremos el error."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y, ¿como usamos esto? Bastante sencillo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto lo que hace es ejecutar la promesa que hemos creado y a continuación ("},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":") se ejecutará la función dentro del "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" donde "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"resultado"}]},{"type":"text","value":" es el parámetro que hemos recibido desde la promesa con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":". En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":". Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom.then().then().then().catch().then().catch()\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":". Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPrimero cambiamos nuestra función "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"sleep"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le pasamos el parámetro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" y devolvemos un string. A continuación creamos otro método que vaya encadenando"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"function heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"De momento dejamos comentada la parte de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" para ver el resultado. Como véis la función recibe un parámetro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":" (este primer parámetro sería lo que nos devuelve la promesa en caso de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":") y también un parámetro extra con el nombre de otro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":", la promesa resultante de nuestra función "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros"}]},{"type":"text","value":", si no necesitaramos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":" no tendríamos porque meterlo dentro de otra función, bastaría solo con usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros(\"New Hero\")"}]},{"type":"text","value":". Bueno y ahora si lo probamos"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png","alt":"Example Multiple promises"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png","alt":"Example Catch without return"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos que cuando le toca el turno a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Green Latern"}]},{"type":"text","value":" pasa por el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" ya que solo hemos puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"console.log"}]},{"type":"text","value":" para que se vea que pasa por allí, para hacer que se detenga podemos poner"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"catch((err) => {\n    throw err  \n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y ahora sí tendríamos un error al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"estilo promesas"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png","alt":"Promises error"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" o al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" según si ha dado error o no."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"Promise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Promise.all"}]},{"type":"text","value":", pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" cuando responda la primera"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"Promise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)"}]},{"type":"text","value":", con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node -v"}]},{"type":"text","value":" podéis ver en que versión estáis y actualizar si lo necesitáis."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Concretamente vamos a hablar de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"async/await"}]},{"type":"text","value":". Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" es esperar a que una función termine y parece ser que como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"best practice"}]},{"type":"text","value":"(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":" para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPartimos de esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Se supone que tenemos que usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" para que el código se espere a que termine la promesa y meterlo todo dentro de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":"...pues vamos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"async function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis simplemente hemos puesto "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":". Ahora vamos a usarlo como si de una promesa normal se tratase"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"asyncPromise().then((result) => console.log(result))\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien ya tenemos todo, ahora vamos a ejecutarlo"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png","alt":"Async Await example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos veeeemosssss un abrazooorrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"promesas","heading":"Promesas"}]},"featureImageSharp":{"base":"nodebaner.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__5a338158333e0f134c248f37","title":"Don't stop the party: Node JS(XI) Autenticación","slug":"dont-stop-the-party-node-js-x-templates-o-vistas-2","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-6.jpg","excerpt":"En este post vamos a centrarnos en algunas de las posibilidades de\nimplementación de autenticación en Node, concretamente hablaremos de lo que se\nconoce como Basic Auth y de JSON Web Token.\n\nBasic Auth\nEste sistema de autenticación es el más sencillo de todos, y a su vez no de lo\nmás seguro, pero puede que para un sistema sencillo o alguna aplicación interna\npueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero\nsi entras....pues bienvenido pásalo bien ;) ).\nVamos a con","custom_excerpt":null,"visibility":"public","created_at_pretty":"29 Sep 2017","published_at_pretty":"10 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-29T11:22:23.000+02:00","published_at":"2017-10-10T10:00:00.000+02:00","updated_at":"2018-01-22T09:36:28.000+01:00","meta_title":null,"meta_description":"Hablaremos de algunas de las posibilidades de autenticación en Node, concretamente hablaremos de lo que se conoce como Basic Auth y de JSON Web Token. ","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"En este post vamos a centrarnos en algunas de las posibilidades de\nimplementación de autenticación en Node, concretamente hablaremos de lo que se\nconoce como Basic Auth y de JSON Web Token.\n\nBasic Auth\nEste sistema de autenticación es el más sencillo de todos, y a su vez no de lo\nmás seguro, pero puede que para un sistema sencillo o alguna aplicación interna\npueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero\nsi entras....pues bienvenido pásalo bien ;) ).\nVamos a configurar por ejemplo nuestra ruta con heros, la que está en el fichero \nninjas.js para que nos solicite un usuario y contraseña.\n\nLo primero de todo como es habitual en Node, usaremos npm para instalar el\nmódulo necesario\n\nnpm install basic-auth --save\n\n\nA continuación lo que hacemos es requerir el módulo como siempre y lo siguiente\nen el middleware que queramos usamos lo que hemos requerido y le pasamos la\nrequest. Esto lo que hará será buscar datos de usuario y contraseña en ella.\n\n//Con esto importamos el módulo\nconst auth = require('basic-auth');\n\n\nY en nuestro middleware\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n\n\nAhora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas\nmás.\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos\nque responder a nuestro cliente desde nuestro middleware con un valor espécifico\nen la cabecera y ya de paso para hacerlo bien le ponemos el código de estado\npertinente (401 en este caso). Pero claro esto no es tan automático como podemos\npensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en\nnuestra constante userLogin, con todo esto de momento nuestro código sería el\nsiguiente\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\n\nSi ahora lo probamos tendríamos esto\n\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que\npongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de\nalguna forma. En un principio esto lo ideal sería tener una base de datos, un\nfichero o similar para comprobar tanto usuario como contraseña, en nuestro caso\nno tenemos implementado nada de esto por lo que de momento lo que haremos será\ncomprobarlo directamente en el código, pero tener en cuenta que en este punto lo\nque haríamos sería comprobar en algún lado que los datos son correctos\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\n\nAhora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña\n\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más\nelegante, no creo que sea lo mejor hacer este código en todos los middleware que\nnecesitemos (bueno si es general para toda la aplicación solo necesitamos\nponerlo en el app.js y crear un middleware que responda a todas las request,\npero ese no creo que sea el escenario en general).\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una\ncarpeta lib que sera la que tendrá las librerías/módulos que creemos o\nimportemos y no lo hagamos con npm. Creamos un fichero auth.js y lo que haremos\nserá exportar el callback al que respondería un middleware\n\n'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n\n\nBásicamente he puesto el mismo código que habíamos añadido antes, solo que al\nfinal le hemos puesto un next() para que continue con el siguiente middleware\nque coincida.\nAhora vamos a módificar nuestra ruta ninjas para que use esto\n\n'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n\n\nHemos importado nuestro módulo y simplemente se lo hemos pasado como primer\nhandler del middleware. A un middleware le podemos pasar todos los handlers que\nqueramos y se irán ejecutando uno detrás de otro según vayan terminando.\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la\ncontraseña porque seguramente el navegador haya almacenado los datos que habéis\nintroducido anteriormente.\nBueno en cuanto a este método de autenticación poco más merece que miremos, es\nbastante sencillo y pueden existir otro tipo de implementaciones pero este sería\nel funcionamiento típico.\n\nJSON Web Token\nY, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero\nalmacenandola en el cliente, lo que aligera un poco la gestión de esto por parte\ndel backend y como su nombre indica lo hacemos en formato JSON.\nEl proceso sería el siguiente. El usuario se autentica con su usuario y\ncontraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el\nbackend una vez que confirma los datos le devuelve al usuario un token. A partir\nde entonces todas las peticiones HTTP del usuario deben ir acompañadas de este\ntoken(cabecera, queryString...). El token se almacena en el lado del cliente de\nalguna forma(sessionStorage o localStorage por ejemplo), lo que hace que no\ntenga que mantener esta información el backend, lo que convierte todo en\nbastante más escalable. El Token es una firma cifrada que el backend descifra y\nverifica al recibirla lo que permite confirmar la identidad del usuario.\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación\npara todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer\nla gestión pertinente del token. También nos provee de algo más de seguridad, ya\nque no usa cookies para mantener información de usuario se pueden evitar ciertos\ntipos de ataques que manipulen la sesión y además podemos hacer que el token\nexpire cada cierto tiempo lo que nos provee de otra capa más de seguridad.\nVamos a hablar un poco del token que recibimos para que entendamos un poco que\ninformación lleva. Este de aqui será un token tipo\n\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n\n\nSi os fijáis bien esta compuesto por tres strings separados por puntos, hablemos\nun poco de cada uno\n\n1º Header\n\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n\n\nEsto básicamente indica el tipo de token y el algoritmo usado para codificar,\nnormalmente es HMAC SHA256. Descodificado sería algo similar a esto:\n\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n\n\n2º Payload/Data\n\neyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n\n\nLa segunda parte tiene datos extra que indicamos nosotros desde el backend que\nse guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este \npayload a parte de la información que queramos nosotros guardar, tiene lo que se\nconoce como claims, son atributos propios que definen el token(aqui\n[http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName] \nmás en detalle), tiene mínimo 2:\n\n * iat: La fecha en la que se creó el token.\n * exp: La fecha de expiración del token. Esto normalmente lo indicamos nosotros\n   desde el backend.\n\nDescodificado este tendría:\n\n{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n\n\n3º Firma/Signature\n\nqVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n\n\nEsta última parte es la que realmente comprobamos en el backend, esta compuesta\nde los 2 strings anteriores codificados en BASE64 junto con una clave secreta \nque indicamos nosotros en el backend, por lo que si lo que descodifica en este\npunto es igual que lo anterior da por sentado que es correcto.\nDescodificado sería:\n\nHMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n\n\nSecret KEY es la clave secreta que hemos usado para codificar. Podemos comprobar\neste token completo en la pagina oficial de JWT.io [https://jwt.io/] solo es\nnecesario copiar el token completo en la parte donde pone ENCODED y poner la\nclave secreta \"Secret KEY\" en la zona donde pone VERIFY SIGNATURE.\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token,\nahora vamos a implantar JWT en Node para que veamos un ejemplo de como se hace\nimplanta.\n\nLo primero de todo como siempre es instalar el módulo de jsonwebtoken con npm.\n\nnpm install jsonwebtoken --save\n\n\nUna vez instalado, vamos a crearnos otra ruta para hacer el login (así repasamos\nun poco), para ello en la carpeta routes creamos el fichero login.js con este\ncontenido\n\nvar express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n\n\nComo siempre requerimos express e instanciamos router, como extra requerimos \nnuestro nuevo módulo jsonwebtoken\n\nconst express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nHacemos que este nuevo middleware responda a peticiones post, necesario ya que\nmandaremos la información en el body, y extraemos el usuario y contraseña para\ncomprobarlos(se podría hacer en el cliente que la contraseña se codificara de\nalguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con\nNode)\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n\nPonemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en\nnuestro caso que usuario y contraseña están bien, pero recordar que esto\nrealmente se debería comprobar en una base de datos o similar, esto es solo para\nagilizar el desarrollo\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n\n\nAhora tenemos donde creamos el token\n\nconst token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n\n\nLe hemos puesto un payload/data en formato JSON(da menos problemas con este\nformato) que contiene el usuario. Luego le hemos indicado la clave secreta para\ncomponer el hash Secret KEY, **IMPORTANTE esto no debería estar así deberíamos\nponerlo en un fichero de configuración o en las variables de entorno de nuestro\nbackend, para extraerlo con process.env... **. Por último le hemos indicado el\ntiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos\nen la página de npm sobre JSON Web token\n[https://www.npmjs.com/package/jsonwebtoken].\nPor último le devolvemos al cliente el token que hemos generado para que lo use\n\nres.json({sucess: true, token: token});\n\n\nYa tenemos nuestra nueva ruta creada, la indicamos en el app.js, importamos la\nnueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente\n\nvar ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n\n\nY le indicamos a express que la use(debajo de la de ninjas por ejemplo)\n\napp.use('/ninjas',ninjas);\napp.use('/login',login);\n\n\nVoilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un\nsoftware tipo POSTMAN o similar que nos permite personalizar como hacemos las\npeticiones HTTP.\nComo hemos configurado le pasamos en el body por post el usuario y contraseña.\n\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si\ncambiamos la contraseña veréis como nos devuelve algún tipo de 401\n\n\nBueno ya tenemos el token.....pero nos falta algún sitio para usarlo,\n¿no?...pues vamos a por ello.\nAl igual que hicimos arriba con Basic Auth vamos a crearnos un módulo para\ngestionar la verificación del login. En la carpeta lib creamos el fichero \nauthJWT.js y ponemos lo siguiente\n\nconst jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n\n\nEl código es bastante simple, recibimos el token por queryString, y lo\nverificamos con jwt.verify pasandole también la clave privada que hemos usado y\nuna vez comprobado saltaría el callback con el error o con el payload\ndescodificado. Recordar clave secreta aqui kaka, tiene que estar en fichero de\nconfiguración o en variable de entorno\n\njwt.verify(token,'Secret KEY',(err,decoded) => {\n\n\nLe he puesto un console.log para que veáis lo que descodifica si todo va bien o\nda error.\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En\neste caso vamos a cambiar el que usamos con Basic Auth y usamos el nuevo con JWT\n. Nos vamos a ninjas.js y ponemos lo siguiente\n\n'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n\n\nComentamos lo que pertenecia a basic-auth y hacemos lo mismo que hicimos antes\npero con JWT y ya lo tendríamos, vamos a probarlo para ello el token que nos ha\ndevuelto antes se lo pasamos como queryString\n\nhttp://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n\n\nY si todo va bien veremos esto\n\ny si por algún motivo el token no es correcto\n\nBueno como hemos visto usar JSON web Token es relativamente sencillo, en este\ncaso no hemos usado base de datos pero lo ideal seria tener los usuarios y\ncontraseñas almacenados en una base de datos, con la contraseña codificada con\nalgún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no\ntenerlos en nuestro código puestos a mano.\nComo extra comentaros que casi todos los métodos de autenticación con token\n(login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo)\nsuelen funcionar de forma similar, es decir un token que almacenamos y pasamos\nen cada petición normalmente en el header con un nombre tipo x-access-token, \nauthorization o similar.\n\nY hasta aquí la parte de autenticación en el siguiente post y el último por el\nmomento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos\nde Promesas que aunque no es propio de NodeJS, es más de JS creo que es útil que\nlas repasemos y también veremos como poner nuestro proceso de Node en cluster \npara aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una\nlinea nueva de post donde hablaremos de MongoDB y ya de paso lo integraremos con\nNode.\n\nNos veeeemossss un abrazooorrrrrr","html":"<!--kg-card-begin: markdown--><p>En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como <strong>Basic Auth</strong> y de <strong>JSON Web Token</strong>.</p>\n<h3 id=\"basicauth\">Basic Auth</h3>\n<p>Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) ).<br>\nVamos a configurar por ejemplo nuestra ruta con <em>heros</em>, la que está en el fichero <em>ninjas.js</em> para que nos solicite un usuario y contraseña.</p>\n<p>Lo primero de todo como es habitual en Node, usaremos <em>npm</em> para instalar el módulo necesario</p>\n<pre><code>npm install basic-auth --save\n</code></pre>\n<p>A continuación lo que hacemos es <em>requerir</em> el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos <em>requerido</em> y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella.</p>\n<pre><code>//Con esto importamos el módulo\nconst auth = require('basic-auth');\n</code></pre>\n<p>Y en nuestro middleware</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n</code></pre>\n<p>Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más.<br>\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante <strong>userLogin</strong>, con todo esto de momento nuestro código sería el siguiente</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:&quot;Somos un monton de ninjas autenticados&quot; })\n});\n</code></pre>\n<p>Si ahora lo probamos tendríamos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png\" alt=\"Http_Auth example1\"><br>\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:&quot;Somos un montón de ninjas autenticados&quot; })\n});\n</code></pre>\n<p>Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png\" alt=\"Http Auth success\"><br>\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el <strong>app.js</strong> y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general).<br>\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta <em>lib</em> que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero <strong>auth.js</strong> y lo que haremos será <em>exportar</em> el <em>callback</em> al que respondería un middleware</p>\n<pre><code>'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) =&gt; {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n</code></pre>\n<p>Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un <strong>next()</strong> para que continue con el siguiente middleware que coincida.<br>\nAhora vamos a módificar nuestra ruta <em>ninjas</em> para que use esto</p>\n<pre><code>'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:&quot;Somos un montón de ninjas autenticados&quot; })\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. <strong>A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando</strong>.<br>\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente.<br>\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico.</p>\n<h3 id=\"jsonwebtoken\">JSON Web Token</h3>\n<p>Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON.<br>\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un <em>token</em>. A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma(<em>sessionStorage o localStorage</em> por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El <em>Token</em> es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario.<br>\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad.<br>\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo</p>\n<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre>\n<p>Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno</p>\n<p><strong>1º Header</strong></p>\n<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n</code></pre>\n<p>Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es <em>HMAC SHA256</em>. Descodificado sería algo similar a esto:</p>\n<pre><code>{\n  &quot;alg&quot;: &quot;HS256&quot;,\n  &quot;typ&quot;: &quot;JWT&quot;\n}\n</code></pre>\n<p><strong>2º Payload/Data</strong></p>\n<pre><code>eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n</code></pre>\n<p>La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este <em>payload</em> a parte de la información que queramos nosotros guardar, tiene lo que se conoce como <em>claims</em>, son atributos propios que definen el token(<a href=\"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName\">aqui</a> más en detalle), tiene mínimo 2:</p>\n<ul>\n<li><em>iat</em>: La fecha en la que se creó el token.</li>\n<li><em>exp</em>: La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend.</li>\n</ul>\n<p>Descodificado este tendría:</p>\n<pre><code>{\n  &quot;user&quot;: &quot;ninja&quot;,\n  &quot;iat&quot;: 1506849851,\n  &quot;exp&quot;: 1507022651\n}\n</code></pre>\n<p><strong>3º Firma/Signature</strong></p>\n<pre><code>qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre>\n<p>Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en <em>BASE64</em> junto con una <em>clave secreta</em> que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto.<br>\nDescodificado sería:</p>\n<pre><code>HMACSHA256(\n  base64UrlEncode(header) + &quot;.&quot; +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n</code></pre>\n<p><em>Secret KEY</em> es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de <a href=\"https://jwt.io/\">JWT.io</a> solo es necesario copiar el token completo en la parte donde pone <em>ENCODED</em> y poner la clave secreta <em>&quot;Secret KEY&quot;</em> en la zona donde pone <em>VERIFY SIGNATURE</em>.<br>\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar <em>JWT</em> en <em>Node</em> para que veamos un ejemplo de como se hace implanta.</p>\n<p>Lo primero de todo como siempre es instalar el módulo de <em>jsonwebtoken</em> con npm.</p>\n<pre><code>npm install jsonwebtoken --save\n</code></pre>\n<p>Una vez instalado, vamos a crearnos otra <em>ruta</em> para hacer el login (así repasamos un poco), para ello en la carpeta <em>routes</em> creamos el fichero <em>login.js</em> con este contenido</p>\n<pre><code>var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: &quot;2 days&quot;});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Como siempre <em>requerimos</em> express e instanciamos <em>router</em>, como extra <em>requerimos</em> nuestro nuevo módulo <strong>jsonwebtoken</strong></p>\n<pre><code>const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n</code></pre>\n<p>Hacemos que este nuevo middleware responda a peticiones <em>post</em>, necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)</p>\n<pre><code>router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n</code></pre>\n<p>Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo</p>\n<pre><code>  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n</code></pre>\n<p>Ahora tenemos donde creamos el token</p>\n<pre><code>const token = jwt.sign({user: user},'Secret KEY',{expiresIn: &quot;2 days&quot;});\n</code></pre>\n<p>Le hemos puesto un <em>payload/data</em> en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash <em>Secret KEY</em>, **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con <em>process.env...</em> **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre <a href=\"https://www.npmjs.com/package/jsonwebtoken\">JSON Web token</a>.<br>\nPor último le devolvemos al cliente el token que hemos generado para que lo use</p>\n<pre><code>res.json({sucess: true, token: token});\n</code></pre>\n<p>Ya tenemos nuestra nueva ruta creada, la indicamos en el <em>app.js</em>, importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente</p>\n<pre><code>var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n</code></pre>\n<p>Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)</p>\n<pre><code>app.use('/ninjas',ninjas);\napp.use('/login',login);\n</code></pre>\n<p>Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo <em>POSTMAN</em> o similar que nos permite personalizar como hacemos las peticiones HTTP.<br>\nComo hemos configurado le pasamos en el <em>body por post</em> el usuario y contraseña.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png\" alt=\"Postman login\"><br>\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png\" alt=\"postman fail login\"></p>\n<p>Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello.<br>\nAl igual que hicimos arriba con <em>Basic Auth</em> vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta <em>lib</em> creamos el fichero <em>authJWT.js</em> y ponemos lo siguiente</p>\n<pre><code>const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) =&gt; {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n</code></pre>\n<p>El código es bastante simple, recibimos el token por <em>queryString</em>, y lo verificamos con <strong>jwt.verify</strong> pasandole también la <em>clave privada</em> que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. <strong>Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno</strong></p>\n<pre><code>jwt.verify(token,'Secret KEY',(err,decoded) =&gt; {\n</code></pre>\n<p>Le he puesto un <em>console.log</em> para que veáis lo que descodifica si todo va bien o da error.<br>\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con <em>Basic Auth</em> y usamos el nuevo con <em>JWT</em>. Nos vamos a <em>ninjas.js</em> y ponemos lo siguiente</p>\n<pre><code>'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:&quot;Somos un monton de ninjas autenticados&quot; })\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Comentamos lo que pertenecia a <em>basic-auth</em> y hacemos lo mismo que hicimos antes pero con <em>JWT</em> y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como <em>queryString</em></p>\n<pre><code>http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n</code></pre>\n<p>Y si todo va bien veremos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png\" alt=\"Token success\"><br>\ny si por algún motivo el token no es correcto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png\" alt=\"Token error\"><br>\nBueno como hemos visto usar <em>JSON web Token</em> es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano.<br>\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el <strong>header</strong> con un nombre tipo <em>x-access-token</em>, <em>authorization</em> o similar.</p>\n<p>Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de <strong>Promesas</strong> que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en <strong>cluster</strong> para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de <strong>MongoDB</strong> y ya de paso lo integraremos con Node.</p>\n<p>Nos veeeemossss un abrazooorrrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-x-templates-o-vistas-2/","canonical_url":null,"uuid":"96fce422-5da1-4ecd-99e6-8fc5f9d47d37","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59ce10cf58177700014ca379","reading_time":11,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como <strong>Basic Auth</strong> y de <strong>JSON Web Token</strong>.</p>\n<h3 id=\"basicauth\">Basic Auth</h3>\n<p>Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) ).<br>\nVamos a configurar por ejemplo nuestra ruta con <em>heros</em>, la que está en el fichero <em>ninjas.js</em> para que nos solicite un usuario y contraseña.</p>\n<p>Lo primero de todo como es habitual en Node, usaremos <em>npm</em> para instalar el módulo necesario</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install basic-auth --save\n</code></pre></div>\n<p>A continuación lo que hacemos es <em>requerir</em> el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos <em>requerido</em> y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Con esto importamos el módulo\nconst auth = require('basic-auth');\n</code></pre></div>\n<p>Y en nuestro middleware</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n</code></pre></div>\n<p>Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más.<br>\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante <strong>userLogin</strong>, con todo esto de momento nuestro código sería el siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n</code></pre></div>\n<p>Si ahora lo probamos tendríamos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png\" alt=\"Http_Auth example1\"><br>\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n</code></pre></div>\n<p>Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png\" alt=\"Http Auth success\"><br>\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el <strong>app.js</strong> y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general).<br>\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta <em>lib</em> que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero <strong>auth.js</strong> y lo que haremos será <em>exportar</em> el <em>callback</em> al que respondería un middleware</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n</code></pre></div>\n<p>Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un <strong>next()</strong> para que continue con el siguiente middleware que coincida.<br>\nAhora vamos a módificar nuestra ruta <em>ninjas</em> para que use esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. <strong>A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando</strong>.<br>\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente.<br>\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico.</p>\n<h3 id=\"jsonwebtoken\">JSON Web Token</h3>\n<p>Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON.<br>\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un <em>token</em>. A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma(<em>sessionStorage o localStorage</em> por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El <em>Token</em> es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario.<br>\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad.<br>\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre></div>\n<p>Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno</p>\n<p><strong>1º Header</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n</code></pre></div>\n<p>Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es <em>HMAC SHA256</em>. Descodificado sería algo similar a esto:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n</code></pre></div>\n<p><strong>2º Payload/Data</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n</code></pre></div>\n<p>La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este <em>payload</em> a parte de la información que queramos nosotros guardar, tiene lo que se conoce como <em>claims</em>, son atributos propios que definen el token(<a href=\"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName\">aqui</a> más en detalle), tiene mínimo 2:</p>\n<ul>\n<li><em>iat</em>: La fecha en la que se creó el token.</li>\n<li><em>exp</em>: La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend.</li>\n</ul>\n<p>Descodificado este tendría:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n</code></pre></div>\n<p><strong>3º Firma/Signature</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre></div>\n<p>Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en <em>BASE64</em> junto con una <em>clave secreta</em> que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto.<br>\nDescodificado sería:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">HMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n</code></pre></div>\n<p><em>Secret KEY</em> es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de <a href=\"https://jwt.io/\">JWT.io</a> solo es necesario copiar el token completo en la parte donde pone <em>ENCODED</em> y poner la clave secreta <em>\"Secret KEY\"</em> en la zona donde pone <em>VERIFY SIGNATURE</em>.<br>\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar <em>JWT</em> en <em>Node</em> para que veamos un ejemplo de como se hace implanta.</p>\n<p>Lo primero de todo como siempre es instalar el módulo de <em>jsonwebtoken</em> con npm.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install jsonwebtoken --save\n</code></pre></div>\n<p>Una vez instalado, vamos a crearnos otra <em>ruta</em> para hacer el login (así repasamos un poco), para ello en la carpeta <em>routes</em> creamos el fichero <em>login.js</em> con este contenido</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Como siempre <em>requerimos</em> express e instanciamos <em>router</em>, como extra <em>requerimos</em> nuestro nuevo módulo <strong>jsonwebtoken</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n</code></pre></div>\n<p>Hacemos que este nuevo middleware responda a peticiones <em>post</em>, necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n</code></pre></div>\n<p>Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n</code></pre></div>\n<p>Ahora tenemos donde creamos el token</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n</code></pre></div>\n<p>Le hemos puesto un <em>payload/data</em> en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash <em>Secret KEY</em>, **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con <em>process.env...</em> **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre <a href=\"https://www.npmjs.com/package/jsonwebtoken\">JSON Web token</a>.<br>\nPor último le devolvemos al cliente el token que hemos generado para que lo use</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.json({sucess: true, token: token});\n</code></pre></div>\n<p>Ya tenemos nuestra nueva ruta creada, la indicamos en el <em>app.js</em>, importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n</code></pre></div>\n<p>Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/ninjas',ninjas);\napp.use('/login',login);\n</code></pre></div>\n<p>Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo <em>POSTMAN</em> o similar que nos permite personalizar como hacemos las peticiones HTTP.<br>\nComo hemos configurado le pasamos en el <em>body por post</em> el usuario y contraseña.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png\" alt=\"Postman login\"><br>\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png\" alt=\"postman fail login\"></p>\n<p>Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello.<br>\nAl igual que hicimos arriba con <em>Basic Auth</em> vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta <em>lib</em> creamos el fichero <em>authJWT.js</em> y ponemos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n</code></pre></div>\n<p>El código es bastante simple, recibimos el token por <em>queryString</em>, y lo verificamos con <strong>jwt.verify</strong> pasandole también la <em>clave privada</em> que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. <strong>Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">jwt.verify(token,'Secret KEY',(err,decoded) => {\n</code></pre></div>\n<p>Le he puesto un <em>console.log</em> para que veáis lo que descodifica si todo va bien o da error.<br>\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con <em>Basic Auth</em> y usamos el nuevo con <em>JWT</em>. Nos vamos a <em>ninjas.js</em> y ponemos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Comentamos lo que pertenecia a <em>basic-auth</em> y hacemos lo mismo que hicimos antes pero con <em>JWT</em> y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como <em>queryString</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n</code></pre></div>\n<p>Y si todo va bien veremos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png\" alt=\"Token success\"><br>\ny si por algún motivo el token no es correcto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png\" alt=\"Token error\"><br>\nBueno como hemos visto usar <em>JSON web Token</em> es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano.<br>\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el <strong>header</strong> con un nombre tipo <em>x-access-token</em>, <em>authorization</em> o similar.</p>\n<p>Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de <strong>Promesas</strong> que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en <strong>cluster</strong> para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de <strong>MongoDB</strong> y ya de paso lo integraremos con Node.</p>\n<p>Nos veeeemossss un abrazooorrrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" y de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"JSON Web Token"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"basicauth"},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) )."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a configurar por ejemplo nuestra ruta con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros"}]},{"type":"text","value":", la que está en el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" para que nos solicite un usuario y contraseña."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero de todo como es habitual en Node, usaremos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":" para instalar el módulo necesario"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install basic-auth --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A continuación lo que hacemos es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerir"}]},{"type":"text","value":" el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerido"}]},{"type":"text","value":" y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"//Con esto importamos el módulo\nconst auth = require('basic-auth');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en nuestro middleware"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"userLogin"}]},{"type":"text","value":", con todo esto de momento nuestro código sería el siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ahora lo probamos tendríamos esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png","alt":"Http_Auth example1"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png","alt":"Http Auth success"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"lib"}]},{"type":"text","value":" que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"auth.js"}]},{"type":"text","value":" y lo que haremos será "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"exportar"}]},{"type":"text","value":" el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"callback"}]},{"type":"text","value":" al que respondería un middleware"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"next()"}]},{"type":"text","value":" para que continue con el siguiente middleware que coincida."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora vamos a módificar nuestra ruta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas"}]},{"type":"text","value":" para que use esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"jsonwebtoken"},"children":[{"type":"text","value":"JSON Web Token"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"token"}]},{"type":"text","value":". A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma("},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"sessionStorage o localStorage"}]},{"type":"text","value":" por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Token"}]},{"type":"text","value":" es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"1º Header"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"HMAC SHA256"}]},{"type":"text","value":". Descodificado sería algo similar a esto:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"2º Payload/Data"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"payload"}]},{"type":"text","value":" a parte de la información que queramos nosotros guardar, tiene lo que se conoce como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"claims"}]},{"type":"text","value":", son atributos propios que definen el token("},{"type":"element","tagName":"a","properties":{"href":"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName"},"children":[{"type":"text","value":"aqui"}]},{"type":"text","value":" más en detalle), tiene mínimo 2:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"iat"}]},{"type":"text","value":": La fecha en la que se creó el token."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"exp"}]},{"type":"text","value":": La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Descodificado este tendría:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"3º Firma/Signature"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"BASE64"}]},{"type":"text","value":" junto con una "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"clave secreta"}]},{"type":"text","value":" que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nDescodificado sería:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"HMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Secret KEY"}]},{"type":"text","value":" es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de "},{"type":"element","tagName":"a","properties":{"href":"https://jwt.io/"},"children":[{"type":"text","value":"JWT.io"}]},{"type":"text","value":" solo es necesario copiar el token completo en la parte donde pone "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ENCODED"}]},{"type":"text","value":" y poner la clave secreta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"\"Secret KEY\""}]},{"type":"text","value":" en la zona donde pone "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"VERIFY SIGNATURE"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":" en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":" para que veamos un ejemplo de como se hace implanta."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero de todo como siempre es instalar el módulo de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"jsonwebtoken"}]},{"type":"text","value":" con npm."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install jsonwebtoken --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Una vez instalado, vamos a crearnos otra "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ruta"}]},{"type":"text","value":" para hacer el login (así repasamos un poco), para ello en la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"routes"}]},{"type":"text","value":" creamos el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"login.js"}]},{"type":"text","value":" con este contenido"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como siempre "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerimos"}]},{"type":"text","value":" express e instanciamos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":", como extra "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerimos"}]},{"type":"text","value":" nuestro nuevo módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"jsonwebtoken"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hacemos que este nuevo middleware responda a peticiones "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"post"}]},{"type":"text","value":", necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora tenemos donde creamos el token"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le hemos puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"payload/data"}]},{"type":"text","value":" en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Secret KEY"}]},{"type":"text","value":", **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"process.env..."}]},{"type":"text","value":" **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre "},{"type":"element","tagName":"a","properties":{"href":"https://www.npmjs.com/package/jsonwebtoken"},"children":[{"type":"text","value":"JSON Web token"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último le devolvemos al cliente el token que hemos generado para que lo use"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.json({sucess: true, token: token});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos nuestra nueva ruta creada, la indicamos en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":", importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/ninjas',ninjas);\napp.use('/login',login);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"POSTMAN"}]},{"type":"text","value":" o similar que nos permite personalizar como hacemos las peticiones HTTP."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo hemos configurado le pasamos en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"body por post"}]},{"type":"text","value":" el usuario y contraseña."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png","alt":"Postman login"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png","alt":"postman fail login"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAl igual que hicimos arriba con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"lib"}]},{"type":"text","value":" creamos el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"authJWT.js"}]},{"type":"text","value":" y ponemos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"El código es bastante simple, recibimos el token por "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"queryString"}]},{"type":"text","value":", y lo verificamos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"jwt.verify"}]},{"type":"text","value":" pasandole también la "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"clave privada"}]},{"type":"text","value":" que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"jwt.verify(token,'Secret KEY',(err,decoded) => {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le he puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"console.log"}]},{"type":"text","value":" para que veáis lo que descodifica si todo va bien o da error."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" y usamos el nuevo con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":". Nos vamos a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" y ponemos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Comentamos lo que pertenecia a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"basic-auth"}]},{"type":"text","value":" y hacemos lo mismo que hicimos antes pero con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":" y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"queryString"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y si todo va bien veremos esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png","alt":"Token success"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\ny si por algún motivo el token no es correcto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png","alt":"Token error"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno como hemos visto usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JSON web Token"}]},{"type":"text","value":" es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"header"}]},{"type":"text","value":" con un nombre tipo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"x-access-token"}]},{"type":"text","value":", "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"authorization"}]},{"type":"text","value":" o similar."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Promesas"}]},{"type":"text","value":" que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"cluster"}]},{"type":"text","value":" para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"MongoDB"}]},{"type":"text","value":" y ya de paso lo integraremos con Node."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos veeeemossss un abrazooorrrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"basicauth","heading":"Basic Auth"},{"id":"jsonwebtoken","heading":"JSON Web Token"}]},"featureImageSharp":{"base":"nodebaner-6.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-6.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-6.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-6.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-6.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-6.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-6.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-6.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-6.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-6.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-6.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-6.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-6.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-6.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-6.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-6.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}}]}},"pageContext":{"slug":"dont-stop-the-party-node-js-ix-rutas","prev":"dont-stop-the-party-node-js-x-templates-o-vistas","next":"dont-stop-the-party-node-js-vii-mvc-y-express","tag":"nodejs","limit":3,"skip":0,"primaryTagCount":13,"collectionPaths":{}}},
    "staticQueryHashes": ["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}