{
    "componentChunkName": "component---node-modules-gatsby-theme-try-ghost-src-templates-tag-js",
    "path": "/tag/nodejs/",
    "result": {"data":{"ghostTag":{"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},"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":{"pageNumber":0,"limit":3,"skip":0,"totalPosts":13,"numberOfPages":5,"humanPageNumber":1,"prevPageNumber":null,"nextPageNumber":2,"previousPagePath":null,"nextPagePath":"/tag/nodejs/page/2/","slug":"nodejs","collectionPaths":{},"iScrollEnabled":true,"postIds":["Ghost__Post__5a338158333e0f134c248f3e","Ghost__Post__5a338158333e0f134c248f38","Ghost__Post__5a338158333e0f134c248f37","Ghost__Post__5a338158333e0f134c248f36","Ghost__Post__5a338158333e0f134c248f35","Ghost__Post__5a338158333e0f134c248f34","Ghost__Post__5a338158333e0f134c248f32","Ghost__Post__5a338158333e0f134c248f31","Ghost__Post__5a338158333e0f134c248f2e","Ghost__Post__5a338158333e0f134c248f2d","Ghost__Post__5a338158333e0f134c248f21","Ghost__Post__5a338158333e0f134c248f20","Ghost__Post__5a338158333e0f134c248f1e"],"cursor":0}},
    "staticQueryHashes": ["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}