{
    "componentChunkName": "component---node-modules-gatsby-theme-try-ghost-src-templates-post-js",
    "path": "/dont-stop-the-party-node-js-v/",
    "result": {"data":{"ghostPost":{"id":"Ghost__Post__5a338158333e0f134c248f2e","title":"Don't stop the party: Node JS(V) Basics","slug":"dont-stop-the-party-node-js-v","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-1.jpg","excerpt":"Tras nuestro repaso de algunas características que nos serían útiles de\nJavaScript, vamos a ver algunas propiedades, métodos o lógicas de NodeJS que nos\nayudarán con el desarrollo de servicios en este lenguaje.\n\nEvent Loop\nNode usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros\nes así, es posible que internamente se ejecute de otra forma pero insisto no\npara nosotros.\nEste hilo funciona como un bucle, es decir, lo que hace en cada vuelta es\nejecutar el código que le toca e","custom_excerpt":null,"visibility":"public","created_at_pretty":"13 Sep 2017","published_at_pretty":"18 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-13T09:13:32.000+02:00","published_at":"2017-09-18T10:35:00.000+02:00","updated_at":"2018-01-22T09:47:10.000+01:00","meta_title":null,"meta_description":"Después de ver algunas cosas que necesitaremos de JavaScript, empezaremos con algunas cosas básicas que tenemos que entender de 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":"Tras nuestro repaso de algunas características que nos serían útiles de\nJavaScript, vamos a ver algunas propiedades, métodos o lógicas de NodeJS que nos\nayudarán con el desarrollo de servicios en este lenguaje.\n\nEvent Loop\nNode usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros\nes así, es posible que internamente se ejecute de otra forma pero insisto no\npara nosotros.\nEste hilo funciona como un bucle, es decir, lo que hace en cada vuelta es\nejecutar el código que le toca en ese momento(todo síncrono), y si se encuentra\nalgún callback lo ejecuta pero, repito pero los va dejando pendientes y\ncomprueba si han terminado en vueltas posteriores y si han terminado entonces\nejecúta sus el código pertinente a ese callback.\nPor este motivo todo el nuestro código en NodeJS tenemos que procurar que sea no\nbloqueante, si puede bloquear de algúna forma el hilo eso significa que tenemos\nque hacerlo asíncrono para que el event loop(nuestro único hilo) no se detenga.\nTodas las llamadas a funciones de entrada/salida lectura/escritura del disco,\nred, base de datos deberia ser asíncrono.\n\nProcess\nProcess es un objeto global que está disponible en nuestras aplicaciones, el\ncual nos va a permitir por ejemplo:\nsaber en que sistema operativo está funcionando,\n\nprocess.platform;\n\n\nparar la ejecución con un código de salida,\n\nprocess.exit(int); //0 para salida correcta\n\n\nresponder a eventos como este de 'exit' con un callback para hacer algo antes de\nparar la ejecución\n\nprocess.on('exit',callback);\n\n\no hacer algo en la siguiente vuelta del event loop\n\nprocess.nextTick(function(){\n    console.log('Siguiente vueltaaaaaaaaaa')\n}\n\n\nEjemplo de información de sistema\n\n'use strict';\n\nvar systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n\n\nCon este código vereis varios ejemplos de información que podemos sacar gracias\na process.\n\nVeamos ahora un ejemplo de exit, para ello vamos poner antes de todos los logs\nlo siguiente\n\nprocess.exit(2);\n\n\nSi ahora ejecutais vereis como se finaliza el programa antes de mostrar nada y\npodéis comprobar el código de salida con\nEn linux/Mac:\n\necho $?\n\n\nEn Windows:\n\necho %errorlevel%\n\n\n\n\nPor último vamos a probar a realizar algo justo antes de salir para ello, vamos\na dejar nuestro código asi:\n\n'use strict';\n\nvar systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nprocess.on('exit', () => { console.log('Antes de salir digo BYEEEEEe')})\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\n\nprocess.exit(0);\n\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n\n\n\nSi ahora ejecutamos esto veréis algo similar a esto\n\nComo veis nos muestra los tres primeros logs y en cuanto llega al exit se\ndespide y ya no nos muestra más, sencillo verdad?\n\nEventEmitter\nEste método puede ser una herramienta muy útil para según que cosa, lo que nos\npermite es asignar una o varias funciones a un evento, es decir, cada vez que\nllamemos a ese evento se ejecutará su función asignada.\nVeamoslo con un ejemplo, antes de nada vamos a importar lo que necesitamos para\nusarlo:\n\n'use strict';\n\nvar events = require('events');\nvar eventEmitter = new events.EventEmitter();\n\n\nYa estamos listos, ahora pensemos en cualquier juego de Mario Bros.. Cada vez\nque nuestro Mario hacia algún tipo de evento distinto a moverse izquierda o\nderecha emitía un sonido, ya fuera saltar, coger alguna moneda o saltar sobre\nalguna inocente tortuga, es decir, a nivel de código tiene que tener un método\nsimilar a playSound no? Pues vamos a crearlo\n\nfunction playSound(){\n    console.log(\"Mario hace algo\");\n}\n\n\nYa tenemos nuestro método, ahora como hemos comentado esto tiene que responder a\nalgún evento, por lo que vamos a asignarle un nombre de evento a ese método\n\neventEmitter.on('play music',playSound);\n\n\nPara llamar a ese evento que hemos creado es tan simple como emitirlo\n\neventEmitter.emit('play music');\n\n\nAsi de simple jejejejeje pero esto realmente si lo pensamos es poco eficiente,\ncon este tendriamos que crear realmente un evento por cada tipo desonido,\nno?......Pues no realmente, también nos permite pasarle parámetros, vamos a\ncambiar nuestro método para que reciba un parámetro donde indicariamos el tipo\nde sonido\n\nfunction playSound(action){\n    console.log(\"Mario \",action);\n}\n\n\nY hagamos que nuestro emit le pase algún parámetro\n\neventEmitter.emit('play music','coge moneda');\n\n\nY voilá si ejecutámos veremos que Mario ha cogido una moneda\n\nComentar que podemos suscribir varias funciones al mismo evento, simplemente\ntendriamos que hacer otro eventEmitter.on con el mismo nombre de evento y otro\nnombre de función, esto lo que haría seria ejecutar ambos.\nY es en este punto donde por ejemplo podemos ver mejor su utilidad, si seguimos\nusando nuestro ejemplo de Mario, supongamos el momento en el que Mario salta\nsobre una tortuga, esto tendría que gestionar entre otras cosas el sonido al\npisar la tortuga, el efecto visual de la tortuga y si esto nos da puntos\ntendríamos que efectuar la gestión de estos. Son bastantes cosas no?....pero si\ntenemos todas estas necesidades subscritas al mismo evento, por ejemplo \nturtleDeath solo tendriamos que hacer\n\neventEmitter.emit('turtleDeath') \n\n\nY listo se ejecutarian todos los eventos y el código quedaría bastante limpio.\n\nCreo que más o menos queda todo claro, en el próximo post hablaremos de los \nmódulos de Node y de como crearlos.\n\nUn abrazooorrrrr","html":"<!--kg-card-begin: markdown--><p>Tras nuestro repaso de algunas características que nos serían útiles de JavaScript, vamos a ver algunas propiedades, métodos o lógicas de <strong>NodeJS</strong> que nos ayudarán con el desarrollo de servicios en este lenguaje.</p>\n<h3 id=\"eventloop\">Event Loop</h3>\n<p>Node usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros es así, es posible que internamente se ejecute de otra forma pero insisto no para nosotros.<br>\nEste hilo funciona como un bucle, es decir, lo que hace en cada vuelta es ejecutar el código que le toca en ese momento(todo síncrono), y si se encuentra algún callback lo ejecuta <strong>pero</strong>, repito <strong>pero</strong> los va dejando pendientes y comprueba si han terminado en vueltas posteriores y si han terminado entonces ejecúta sus el código pertinente a ese callback.<br>\nPor este motivo todo el nuestro código en <strong>NodeJS</strong> tenemos que procurar que sea no bloqueante, si puede bloquear de algúna forma el hilo eso significa que tenemos que hacerlo asíncrono para que el event loop(nuestro único hilo) no se detenga. Todas las llamadas a funciones de entrada/salida lectura/escritura del disco, red, base de datos deberia ser asíncrono.</p>\n<h3 id=\"process\">Process</h3>\n<p>Process es un objeto global que está disponible en nuestras aplicaciones, el cual nos va a permitir por ejemplo:<br>\nsaber en que sistema operativo está funcionando,</p>\n<pre><code>process.platform;\n</code></pre>\n<p>parar la ejecución con un código de salida,</p>\n<pre><code>process.exit(int); //0 para salida correcta\n</code></pre>\n<p>responder a eventos como este de <strong>'exit'</strong> con un callback para hacer algo antes de parar la ejecución</p>\n<pre><code>process.on('exit',callback);\n</code></pre>\n<p>o hacer algo en la siguiente vuelta del <strong>event loop</strong></p>\n<pre><code>process.nextTick(function(){\n    console.log('Siguiente vueltaaaaaaaaaa')\n}\n</code></pre>\n<p>Ejemplo de información de sistema</p>\n<pre><code>'use strict';\n\nvar systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n</code></pre>\n<p>Con este código vereis varios ejemplos de información que podemos sacar gracias a process.</p>\n<p>Veamos ahora un ejemplo de <strong>exit</strong>, para ello vamos poner antes de todos los logs lo siguiente</p>\n<pre><code>process.exit(2);\n</code></pre>\n<p>Si ahora ejecutais vereis como se finaliza el programa antes de mostrar nada y podéis comprobar el código de salida con<br>\nEn linux/Mac:</p>\n<pre><code>echo $?\n</code></pre>\n<p>En Windows:</p>\n<pre><code>echo %errorlevel%\n</code></pre>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.46.31.png\" alt=\"Error Code\"></p>\n<p>Por último vamos a probar a realizar algo justo antes de salir para ello, vamos a dejar nuestro código asi:</p>\n<pre><code>'use strict';\n\nvar systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nprocess.on('exit', () =&gt; { console.log('Antes de salir digo BYEEEEEe')})\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\n\nprocess.exit(0);\n\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n\n</code></pre>\n<p>Si ahora ejecutamos esto veréis algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.51.57.png\" alt=\"Log exit event\"><br>\nComo veis nos muestra los tres primeros logs y en cuanto llega al exit se despide y ya no nos muestra más, sencillo verdad?</p>\n<h3 id=\"eventemitter\">EventEmitter</h3>\n<p>Este método puede ser una herramienta muy útil para según que cosa, lo que nos permite es asignar una o varias funciones a un evento, es decir, cada vez que llamemos a ese evento se ejecutará su función asignada.<br>\nVeamoslo con un ejemplo, antes de nada vamos a importar lo que necesitamos para usarlo:</p>\n<pre><code>'use strict';\n\nvar events = require('events');\nvar eventEmitter = new events.EventEmitter();\n</code></pre>\n<p>Ya estamos listos, ahora pensemos en cualquier juego de <strong>Mario Bros.</strong>. Cada vez que nuestro Mario hacia algún tipo de evento distinto a moverse izquierda o derecha emitía un sonido, ya fuera saltar, coger alguna moneda o saltar sobre alguna inocente tortuga, es decir, a nivel de código tiene que tener un método similar a <strong>playSound</strong> no? Pues vamos a crearlo</p>\n<pre><code>function playSound(){\n    console.log(&quot;Mario hace algo&quot;);\n}\n</code></pre>\n<p>Ya tenemos nuestro método, ahora como hemos comentado esto tiene que responder a algún evento, por lo que vamos a asignarle un nombre de evento a ese método</p>\n<pre><code>eventEmitter.on('play music',playSound);\n</code></pre>\n<p>Para llamar a ese evento que hemos creado es tan simple como <strong>emitirlo</strong></p>\n<pre><code>eventEmitter.emit('play music');\n</code></pre>\n<p>Asi de simple jejejejeje pero esto realmente si lo pensamos es poco eficiente, con este tendriamos que crear realmente un evento por cada tipo desonido, no?......Pues no realmente, también nos permite pasarle parámetros, vamos a cambiar nuestro método para que reciba un parámetro donde indicariamos el tipo de sonido</p>\n<pre><code>function playSound(action){\n    console.log(&quot;Mario &quot;,action);\n}\n</code></pre>\n<p>Y hagamos que nuestro <strong>emit</strong> le pase algún parámetro</p>\n<pre><code>eventEmitter.emit('play music','coge moneda');\n</code></pre>\n<p>Y voilá si ejecutámos veremos que <strong>Mario ha cogido una moneda</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-09.04.01.png\" alt=\"EventEmitter example\"><br>\nComentar que podemos suscribir varias funciones al mismo evento, simplemente tendriamos que hacer otro <strong>eventEmitter.on</strong> con el mismo nombre de evento y otro nombre de función, esto lo que haría seria ejecutar ambos.<br>\nY es en este punto donde por ejemplo podemos ver mejor su utilidad, si seguimos usando nuestro ejemplo de Mario, supongamos el momento en el que Mario salta sobre una tortuga, esto tendría que gestionar entre otras cosas el sonido al pisar la tortuga, el efecto visual de la tortuga y si esto nos da puntos tendríamos que efectuar la gestión de estos. Son bastantes cosas no?....pero si tenemos todas estas necesidades subscritas al mismo evento, por ejemplo <strong>turtleDeath</strong> solo tendriamos que hacer</p>\n<pre><code>eventEmitter.emit('turtleDeath') \n</code></pre>\n<p>Y listo se ejecutarian todos los eventos y el código quedaría bastante limpio.</p>\n<p>Creo que más o menos queda todo claro, en el próximo post hablaremos de los <strong>módulos</strong> de Node y de como crearlos.</p>\n<p>Un abrazooorrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/","canonical_url":null,"uuid":"1fe4938b-6348-4f8e-b92a-029ec8a1d8ae","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59b8da9c6c31a60001f69f26","reading_time":4,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Tras nuestro repaso de algunas características que nos serían útiles de JavaScript, vamos a ver algunas propiedades, métodos o lógicas de <strong>NodeJS</strong> que nos ayudarán con el desarrollo de servicios en este lenguaje.</p>\n<h3 id=\"eventloop\">Event Loop</h3>\n<p>Node usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros es así, es posible que internamente se ejecute de otra forma pero insisto no para nosotros.<br>\nEste hilo funciona como un bucle, es decir, lo que hace en cada vuelta es ejecutar el código que le toca en ese momento(todo síncrono), y si se encuentra algún callback lo ejecuta <strong>pero</strong>, repito <strong>pero</strong> los va dejando pendientes y comprueba si han terminado en vueltas posteriores y si han terminado entonces ejecúta sus el código pertinente a ese callback.<br>\nPor este motivo todo el nuestro código en <strong>NodeJS</strong> tenemos que procurar que sea no bloqueante, si puede bloquear de algúna forma el hilo eso significa que tenemos que hacerlo asíncrono para que el event loop(nuestro único hilo) no se detenga. Todas las llamadas a funciones de entrada/salida lectura/escritura del disco, red, base de datos deberia ser asíncrono.</p>\n<h3 id=\"process\">Process</h3>\n<p>Process es un objeto global que está disponible en nuestras aplicaciones, el cual nos va a permitir por ejemplo:<br>\nsaber en que sistema operativo está funcionando,</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.platform;\n</code></pre></div>\n<p>parar la ejecución con un código de salida,</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.exit(int); //0 para salida correcta\n</code></pre></div>\n<p>responder a eventos como este de <strong>'exit'</strong> con un callback para hacer algo antes de parar la ejecución</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.on('exit',callback);\n</code></pre></div>\n<p>o hacer algo en la siguiente vuelta del <strong>event loop</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.nextTick(function(){\n    console.log('Siguiente vueltaaaaaaaaaa')\n}\n</code></pre></div>\n<p>Ejemplo de información de sistema</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 systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n</code></pre></div>\n<p>Con este código vereis varios ejemplos de información que podemos sacar gracias a process.</p>\n<p>Veamos ahora un ejemplo de <strong>exit</strong>, para ello vamos poner antes de todos los logs lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.exit(2);\n</code></pre></div>\n<p>Si ahora ejecutais vereis como se finaliza el programa antes de mostrar nada y podéis comprobar el código de salida con<br>\nEn linux/Mac:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">echo $?\n</code></pre></div>\n<p>En Windows:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">echo %errorlevel%\n</code></pre></div>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.46.31.png\" alt=\"Error Code\"></p>\n<p>Por último vamos a probar a realizar algo justo antes de salir para ello, vamos a dejar nuestro código asi:</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 systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nprocess.on('exit', () => { console.log('Antes de salir digo BYEEEEEe')})\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\n\nprocess.exit(0);\n\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n\n</code></pre></div>\n<p>Si ahora ejecutamos esto veréis algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.51.57.png\" alt=\"Log exit event\"><br>\nComo veis nos muestra los tres primeros logs y en cuanto llega al exit se despide y ya no nos muestra más, sencillo verdad?</p>\n<h3 id=\"eventemitter\">EventEmitter</h3>\n<p>Este método puede ser una herramienta muy útil para según que cosa, lo que nos permite es asignar una o varias funciones a un evento, es decir, cada vez que llamemos a ese evento se ejecutará su función asignada.<br>\nVeamoslo con un ejemplo, antes de nada vamos a importar lo que necesitamos para usarlo:</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 events = require('events');\nvar eventEmitter = new events.EventEmitter();\n</code></pre></div>\n<p>Ya estamos listos, ahora pensemos en cualquier juego de <strong>Mario Bros.</strong>. Cada vez que nuestro Mario hacia algún tipo de evento distinto a moverse izquierda o derecha emitía un sonido, ya fuera saltar, coger alguna moneda o saltar sobre alguna inocente tortuga, es decir, a nivel de código tiene que tener un método similar a <strong>playSound</strong> no? Pues vamos a crearlo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function playSound(){\n    console.log(\"Mario hace algo\");\n}\n</code></pre></div>\n<p>Ya tenemos nuestro método, ahora como hemos comentado esto tiene que responder a algún evento, por lo que vamos a asignarle un nombre de evento a ese método</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eventEmitter.on('play music',playSound);\n</code></pre></div>\n<p>Para llamar a ese evento que hemos creado es tan simple como <strong>emitirlo</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eventEmitter.emit('play music');\n</code></pre></div>\n<p>Asi de simple jejejejeje pero esto realmente si lo pensamos es poco eficiente, con este tendriamos que crear realmente un evento por cada tipo desonido, no?......Pues no realmente, también nos permite pasarle parámetros, vamos a cambiar nuestro método para que reciba un parámetro donde indicariamos el tipo de sonido</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function playSound(action){\n    console.log(\"Mario \",action);\n}\n</code></pre></div>\n<p>Y hagamos que nuestro <strong>emit</strong> le pase algún parámetro</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eventEmitter.emit('play music','coge moneda');\n</code></pre></div>\n<p>Y voilá si ejecutámos veremos que <strong>Mario ha cogido una moneda</strong><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-09.04.01.png\" alt=\"EventEmitter example\"><br>\nComentar que podemos suscribir varias funciones al mismo evento, simplemente tendriamos que hacer otro <strong>eventEmitter.on</strong> con el mismo nombre de evento y otro nombre de función, esto lo que haría seria ejecutar ambos.<br>\nY es en este punto donde por ejemplo podemos ver mejor su utilidad, si seguimos usando nuestro ejemplo de Mario, supongamos el momento en el que Mario salta sobre una tortuga, esto tendría que gestionar entre otras cosas el sonido al pisar la tortuga, el efecto visual de la tortuga y si esto nos da puntos tendríamos que efectuar la gestión de estos. Son bastantes cosas no?....pero si tenemos todas estas necesidades subscritas al mismo evento, por ejemplo <strong>turtleDeath</strong> solo tendriamos que hacer</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eventEmitter.emit('turtleDeath') \n</code></pre></div>\n<p>Y listo se ejecutarian todos los eventos y el código quedaría bastante limpio.</p>\n<p>Creo que más o menos queda todo claro, en el próximo post hablaremos de los <strong>módulos</strong> de Node y de como crearlos.</p>\n<p>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":"Tras nuestro repaso de algunas características que nos serían útiles de JavaScript, vamos a ver algunas propiedades, métodos o lógicas de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":" que nos ayudarán con el desarrollo de servicios en este lenguaje."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"eventloop"},"children":[{"type":"text","value":"Event Loop"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Node usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros es así, es posible que internamente se ejecute de otra forma pero insisto no para nosotros."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEste hilo funciona como un bucle, es decir, lo que hace en cada vuelta es ejecutar el código que le toca en ese momento(todo síncrono), y si se encuentra algún callback lo ejecuta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"pero"}]},{"type":"text","value":", repito "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"pero"}]},{"type":"text","value":" los va dejando pendientes y comprueba si han terminado en vueltas posteriores y si han terminado entonces ejecúta sus el código pertinente a ese callback."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor este motivo todo el nuestro código en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":" tenemos que procurar que sea no bloqueante, si puede bloquear de algúna forma el hilo eso significa que tenemos que hacerlo asíncrono para que el event loop(nuestro único hilo) no se detenga. Todas las llamadas a funciones de entrada/salida lectura/escritura del disco, red, base de datos deberia ser asíncrono."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"process"},"children":[{"type":"text","value":"Process"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Process es un objeto global que está disponible en nuestras aplicaciones, el cual nos va a permitir por ejemplo:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nsaber en que sistema operativo está funcionando,"}]},{"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.platform;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"parar la ejecución con un código de salida,"}]},{"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.exit(int); //0 para salida correcta\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"responder a eventos como este de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"'exit'"}]},{"type":"text","value":" con un callback para hacer algo antes de parar la ejecución"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"process.on('exit',callback);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"o hacer algo en la siguiente vuelta del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"event loop"}]}]},{"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.nextTick(function(){\n    console.log('Siguiente vueltaaaaaaaaaa')\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ejemplo de información de sistema"}]},{"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 systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con este código vereis varios ejemplos de información que podemos sacar gracias a process."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos ahora un ejemplo de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"exit"}]},{"type":"text","value":", para ello vamos poner antes de todos los logs 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":"process.exit(2);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ahora ejecutais vereis como se finaliza el programa antes de mostrar nada y podéis comprobar el código de salida con"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn linux/Mac:"}]},{"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":"echo $?\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En Windows:"}]},{"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":"echo %errorlevel%\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.46.31.png","alt":"Error Code"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Por último vamos a probar a realizar algo justo antes de salir para ello, vamos a dejar nuestro código asi:"}]},{"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 systemInfo = {\n    pid: process.pid,\n    version: process.version,\n    platform: process.platform,\n    title: process.title,\n    arg: process.argv,\n    execPath: process.execPath,\n    folder: process.cwd()\n};\n\nprocess.on('exit', () => { console.log('Antes de salir digo BYEEEEEe')})\n\nconsole.log('Id de proceso ' + systemInfo.pid)\nconsole.log('Versión de Node' + systemInfo.version)\nconsole.log('Plataforma ' + systemInfo.platform)\n\nprocess.exit(0);\n\nconsole.log('Nombre de proceso ' + systemInfo.title)\nconsole.log('Argumentos que recibe ' + systemInfo.arg)\nconsole.log('Path de ejecución de proceso '+ systemInfo.execPath)\nconsole.log('Path de ejecución de aplicación de node '+ systemInfo.folder)\n\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ahora ejecutamos esto veréis algo similar a esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.51.57.png","alt":"Log exit event"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis nos muestra los tres primeros logs y en cuanto llega al exit se despide y ya no nos muestra más, sencillo verdad?"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"eventemitter"},"children":[{"type":"text","value":"EventEmitter"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este método puede ser una herramienta muy útil para según que cosa, lo que nos permite es asignar una o varias funciones a un evento, es decir, cada vez que llamemos a ese evento se ejecutará su función asignada."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVeamoslo con un ejemplo, antes de nada vamos a importar lo que necesitamos para usarlo:"}]},{"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 events = require('events');\nvar eventEmitter = new events.EventEmitter();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya estamos listos, ahora pensemos en cualquier juego de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mario Bros."}]},{"type":"text","value":". Cada vez que nuestro Mario hacia algún tipo de evento distinto a moverse izquierda o derecha emitía un sonido, ya fuera saltar, coger alguna moneda o saltar sobre alguna inocente tortuga, es decir, a nivel de código tiene que tener un método similar a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"playSound"}]},{"type":"text","value":" no? Pues vamos a crearlo"}]},{"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 playSound(){\n    console.log(\"Mario hace algo\");\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos nuestro método, ahora como hemos comentado esto tiene que responder a algún evento, por lo que vamos a asignarle un nombre de evento a ese método"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eventEmitter.on('play music',playSound);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para llamar a ese evento que hemos creado es tan simple como "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"emitirlo"}]}]},{"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":"eventEmitter.emit('play music');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Asi de simple jejejejeje pero esto realmente si lo pensamos es poco eficiente, con este tendriamos que crear realmente un evento por cada tipo desonido, no?......Pues no realmente, también nos permite pasarle parámetros, vamos a cambiar nuestro método para que reciba un parámetro donde indicariamos el tipo de sonido"}]},{"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 playSound(action){\n    console.log(\"Mario \",action);\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y hagamos que nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"emit"}]},{"type":"text","value":" le pase algún parámetro"}]},{"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":"eventEmitter.emit('play music','coge moneda');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y voilá si ejecutámos veremos que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mario ha cogido una moneda"}]},{"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-15-at-09.04.01.png","alt":"EventEmitter example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComentar que podemos suscribir varias funciones al mismo evento, simplemente tendriamos que hacer otro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"eventEmitter.on"}]},{"type":"text","value":" con el mismo nombre de evento y otro nombre de función, esto lo que haría seria ejecutar ambos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nY es en este punto donde por ejemplo podemos ver mejor su utilidad, si seguimos usando nuestro ejemplo de Mario, supongamos el momento en el que Mario salta sobre una tortuga, esto tendría que gestionar entre otras cosas el sonido al pisar la tortuga, el efecto visual de la tortuga y si esto nos da puntos tendríamos que efectuar la gestión de estos. Son bastantes cosas no?....pero si tenemos todas estas necesidades subscritas al mismo evento, por ejemplo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"turtleDeath"}]},{"type":"text","value":" solo tendriamos que hacer"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eventEmitter.emit('turtleDeath') \n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y listo se ejecutarian todos los eventos y el código quedaría bastante limpio."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Creo que más o menos queda todo claro, en el próximo post hablaremos de los "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"módulos"}]},{"type":"text","value":" de Node y de como crearlos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un abrazooorrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"eventloop","heading":"Event Loop"},{"id":"process","heading":"Process"},{"id":"eventemitter","heading":"EventEmitter"}]},"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":4,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner-1.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/65d8c/nodebaner-1.jpg 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/c5f21/nodebaner-1.jpg 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner-1.jpg 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/81a53/nodebaner-1.jpg 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-1.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner-1.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/dc8f3/nodebaner-1.webp 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/2db4b/nodebaner-1.webp 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner-1.webp 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/f5845/nodebaner-1.webp 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-1.webp 1680w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"prev":{"id":"Ghost__Post__5a338158333e0f134c248f31","title":"Don't stop the party: Node JS(VI) Módulos y NPM","slug":"dont-stop-the-party-node-js-vi-modulos","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-2.jpg","excerpt":"En este punto vamos a empezar con los módulos que son una parte muy importante y\nmuy útil realmente.\n\nQue son?\nBien los módulos básicamente son código JavaScript que utilizamos como si de una\nlibrería externa se tratase, es decir los importamos. Normalmente estos módulos\nse encuentran en una carpeta llamada node_modules en nuestro proyecto, que se\ncrea automáticamente cuando instalamos algo con npm, por ejemplo. Pero claro no\nhemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la","custom_excerpt":null,"visibility":"public","created_at_pretty":"15 Sep 2017","published_at_pretty":"21 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-15T20:32:13.000+02:00","published_at":"2017-09-21T10:03:00.000+02:00","updated_at":"2018-01-22T09:45:36.000+01:00","meta_title":null,"meta_description":"Empezaremos a ver qué son los Módulos en JS y como podemos usar NPM para descargarnos los ya creados.","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 punto vamos a empezar con los módulos que son una parte muy importante y\nmuy útil realmente.\n\nQue son?\nBien los módulos básicamente son código JavaScript que utilizamos como si de una\nlibrería externa se tratase, es decir los importamos. Normalmente estos módulos\nse encuentran en una carpeta llamada node_modules en nuestro proyecto, que se\ncrea automáticamente cuando instalamos algo con npm, por ejemplo. Pero claro no\nhemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la línea de\ncomandos (con la posición o ubicación en el path de vuestro proyecto) y poner\n\nnpm install async\n\n\nAsync es un módulo de npm que nos ayuda con la gestión de código asíncrono(como\nlo hace Node recordemos el event loop ;) ). De primeras al ejecutar el comando\nveréis algo similar a esto\n\nDe momento no hagáis mucho caso a lo que pone ya entraremos en eso más adelante,\nlo que quería mostraros es que si miráis vuestra carpeta de proyecto os ha\ncreado una nueva carpeta llamada node_modules y si miráis lo que hay dentro\npodréis ver que os ha descargado dos carpetas y estas a su vez tienen un montón\nde ficheros y carpetas no?....pues esto son módulos, prácticamente cada fichero \njs esta configurado como un módulo.\n\nAhora que ya hemos visto un poco como es un módulo, hablemos un poco más en\ndetalle de ellos.\nEstán basados en el estándar CommonJS [http://requirejs.org/docs/commonjs.html] \ny para usarlos tenemos que cargarlos en nuestros ficheros js, esto lo hacemos\ncon la instrucción require.Esta instrucción es síncrona, es decir, no puede\nhacerse en un callback ni nada por el estilo.\nAlgo bueno que tienen los módulos es que son singletons\n[http://www.oodesign.com/singleton-pattern.html], que para el que no sepa que\nes, es un patrón de diseño con el cual nos aseguramos que solo tenemos una\ninstancia de un objeto, como puede ser una conexion a una base de datos. Lo que\nhace es que la primera vez que ejecutamos el require se ejecuta el código\nnecesario para crear una instancia nueva de nuestro módulo, el resto de veces\nque llamemos a require para el mismo módulo nos devolverá la misma instancia que\nse habia creado previamente.\nPero, y como sabe lo que tiene que devolver al hacer el require?...Si miráis\ncualquier módulo veréis que al final tienen siempre algo parecido a esto\n\nmodule.exports = nombreAlgunaFunciónUObjeto;\n\n\nEso es lo que realmente se importa, lo que está indicado en esa línea. Y para\nimportar lo que haríamos sería\n\nvar nombre = require ('nombreAlgunaFunciónUObjeto');\n\n\nCon lo que quedaría almacenado en esa variable lo que se había exportado. Lo que\ncontenga el require depende un poco de donde se encuentre el fichero o el script\ndel cual queremos importar y de donde esté nuestra aplicación de Node. Como tal\ntenemos varias opciones\n\n * Que esté en la carpeta node_modules local, es decir, la que nos ha creado en\n   nuestro proyecto cuando hemos usado npm install\n * Puede encontrarse también en la carpeta node_modules global, ésta la crea npm\n   al instalar node, y nosotros podemos almacenar módulos en ella usando npm\n   install -g nombreMódulo\n * Si lo que ponemos empieza por './', '../' o similar lo buscará en la ruta que\n   indiquemos partiendo de la nuestra (la del fichero donde usamos el require)\n * Si es un módulo del propio core de node con poner el nombre seria suficiente\n\nSi tenemos que usar la ruta específica puede que tengamos que poner una ruta\nlarguisima, esto se puede evitar de varias formas usando la variable de entorno \nNODE PATH o a partir de la versión 2.0 de npm podríamos ponerlo en el fichero \npackaje.json (ya hablaremos de él). Si tenéis curiosidad sobre como serían estas\nformas navegar por el ciber-espacio que ya hay mucha literatura sobre esto.\n\nAntes de terminar este post hagamos un ejemplo creando nuestro propio módulo.\nVamos a usar la carpeta node_modules que ya tenemos, y lo que hacemos es crear\ndentro un fichero js nuevo con nombre heroName.js y ponemos este código\n\n'use strict';\n\nvar heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nmodule.exports = heroName;\n\n\nY ahora fuera de la carpeta node_modules en nuestro proyecto creamos otro\nfichero js que yo lo he llamado modules.js y es tan simple como poner\n\n'use strict';\n\nvar heroName = require('heroName');\n\nheroName(\"Dr.Manhattan\")\n\n\nY listo, como véis es algo bastante simple y funciona\n\n\nTambiés es posible exportar más de un método u objeto, para ello cambiemos un\npoco el código de nuestro módulo\n\n'use strict';\n\nvar heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nvar powerLevel = function(power){\n    console.log(\"Power level es:\",power);\n}\n\nmodule.exports = {\n    heroName: heroName,\n    powerLevel: powerLevel\n}\n\n\nY para usarlo, ahora nuestro require realmente devuelve un objeto con 2 métodos\nen él por lo que para usarlos\n\n'use strict';\n\nvar hero = require('heroName');\n\nconsole.log(hero);\n\nhero.heroName(\"Dr.Manhattan\");\n\nhero.powerLevel(\"9000\");\n\n\nHe añadido un log de nuesto objeto hero para que veáis lo que contiene\n\n\nSi os fijáis ahora hero es un objeto con dos propiedades que realmente son dos\nfunciones, las cuales podemos usar tranquilamente como si de cualquier otro\nmétodo se tratara.\n\nNPM\nSon las siglas de Node Package Manager,y lo que nos permite es gestionar las\ndependencias de nuestra aplicación o proyecto, las instala, elimina o actualiza.\nY también nos permite instalarlas de manera global para que podamos usarlas en\ncualquier proyecto.\nNPM se apoya en un fichero llamado package.json que nos ayuda a mantener\ninformación de las dependencias de nuestro proyecto y las versiones que usamos.\n\nSi comenzamos con un proyecto nuevo lo primero que deberiamos hacer es ejecutar\n\nnpm init\n\n\nEsto lo que haría sería crearnos un fichero package.json preguntandonos ciertas\ncosas sobre nuestro proyecto para luego almacenarlas en ese fichero\n\n\nTenemps algunas cosas útiles como por ejemplo la parte de scripts que vemos en\nel fichero. Lo que pongamos en esos scripts actuará como alias de algún comando\nque queramos ejecutar, por ejemplo podemos poner:\n\n  \"scripts\": {\n    \"test\": \"node test.js\",\n    \"start\": \"node callbacks.js\"\n  },\n\n\nCon esto solo tendríamos que poner npm seguido de nuestro nombre de script para\nejecutarlo\n\nnpm start\n\n\n\nComo vemos se ejecuta el fichero que ya creamos en algún post anterior. Puede\nque este caso no tenga mucha utilidad, pero si en lugar de ese comando tan\nsimple tuvieramos que añadirle parámetros o queremos llamar a más elementos en\nla misma ejecución puede ser muy útil.\n\nPara gestionar las dependencias de Node y que se guarden en nuestro package.json \nsolo tenemos que ejecutar el comando de instalación de npm seguido de --save\n\nnpm install json --save\n\n\nAhora nuestro fichero package.json tendría esta pinta\n\n\nVemos que nos ha añadido la dependencia json con su número de versión.\n\nTambién hemos comentado que podemos instalar dependencias de manera global en\nnuestro equipo, para ello con que ejecutemos\n\nnpm install -g jslint\n\n\nEsto nos instalará en /usr/local/lib/node_modules/ la dependencia y creará un\nacceso directo o enlace simbólico en /usr/local/bin para que podamos ejecutarla\ndesde cualquier sitio si es necesario.\n\n\nPor último un detalle en cuanto las versiones de las dependencias, si os fijáis\nantes del número de versión pone un ^ y ¿por qué?....pues significa que npm\npuede actualizar esa dependencia siempre y cuando la versión no modifique el\nvalor más a la izquierda que sea distinto de cero, es decir, si tenemos la\nversión\n\n^9.0.6\n\n\nEl 9 no podría modificarlo, eso significa que la versión en este caso puede\npasar de 9.0.7 a 9.X.X, pero si la versión que tenemos es\n\n^0.2.5\n\n\nEntonces la versión solo puede estar entre 0.2.5 a 0.2.X siendo X mayor que 5.\n\nEn el próximo post empezaremos ya con express y el trabaj o propio de node.\n\nUn abrazooorrrr","html":"<!--kg-card-begin: markdown--><p>En este punto vamos a empezar con los módulos que son una parte muy importante y muy útil realmente.</p>\n<h2 id=\"queson\">Que son?</h2>\n<p>Bien los módulos básicamente son código JavaScript que utilizamos como si de una librería externa se tratase, es decir los importamos. Normalmente estos módulos se encuentran en una carpeta llamada <strong>node_modules</strong> en nuestro proyecto, que se crea automáticamente cuando instalamos algo con <strong>npm</strong>, por ejemplo. Pero claro no hemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la línea de comandos (con la posición o ubicación en el path de vuestro proyecto) y poner</p>\n<pre><code>npm install async\n</code></pre>\n<p>Async es un módulo de npm que nos ayuda con la gestión de código asíncrono(como lo hace Node recordemos el event loop ;) ). De primeras al ejecutar el comando veréis algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-20.42.12.png\" alt=\"Npm example\"><br>\nDe momento no hagáis mucho caso a lo que pone ya entraremos en eso más adelante, lo que quería mostraros es que si miráis vuestra carpeta de proyecto os ha creado una nueva carpeta llamada <strong>node_modules</strong> y si miráis lo que hay dentro podréis ver que os ha descargado dos carpetas y estas a su vez tienen un montón de ficheros y carpetas no?....pues esto son módulos, prácticamente cada fichero <strong>js</strong> esta configurado como un módulo.</p>\n<p>Ahora que ya hemos visto un poco como es un módulo, hablemos un poco más en detalle de ellos.<br>\nEstán basados en el estándar <a href=\"http://requirejs.org/docs/commonjs.html\">CommonJS</a> y para usarlos tenemos que <strong>cargarlos</strong> en nuestros ficheros js, esto lo hacemos con la instrucción <strong>require</strong>.Esta instrucción es <strong>síncrona</strong>, es decir, no puede hacerse en un callback ni nada por el estilo.<br>\nAlgo bueno que tienen los módulos es que son <a href=\"http://www.oodesign.com/singleton-pattern.html\"><strong>singletons</strong></a>, que para el que no sepa que es, es un patrón de diseño con el cual nos aseguramos que solo tenemos una instancia de un objeto, como puede ser una conexion a una base de datos. Lo que hace es que la primera vez que ejecutamos el <strong>require</strong> se ejecuta el código necesario para crear una instancia nueva de nuestro módulo, el resto de veces que llamemos a <strong>require</strong> para el mismo módulo nos devolverá la misma instancia que se habia creado previamente.<br>\nPero, y como sabe lo que tiene que devolver al hacer el <strong>require</strong>?...Si miráis cualquier módulo veréis que al final tienen siempre algo parecido a esto</p>\n<pre><code>module.exports = nombreAlgunaFunciónUObjeto;\n</code></pre>\n<p>Eso es lo que realmente se importa, lo que está indicado en esa línea. Y para importar lo que haríamos sería</p>\n<pre><code>var nombre = require ('nombreAlgunaFunciónUObjeto');\n</code></pre>\n<p>Con lo que quedaría almacenado en esa variable lo que se había exportado. Lo que contenga el <strong>require</strong> depende un poco de donde se encuentre el fichero o el script del cual queremos importar y de donde esté nuestra aplicación de Node. Como tal tenemos varias opciones</p>\n<ul>\n<li>Que esté en la carpeta <strong>node_modules</strong> local, es decir, la que nos ha creado en nuestro proyecto cuando hemos usado <strong>npm install</strong></li>\n<li>Puede encontrarse también en la carpeta <strong>node_modules</strong> global, ésta la crea npm al instalar node, y nosotros podemos almacenar módulos en ella usando <strong>npm install -g nombreMódulo</strong></li>\n<li>Si lo que ponemos empieza por './', '../' o similar lo buscará en la ruta que indiquemos partiendo de la nuestra (la del fichero donde usamos el require)</li>\n<li>Si es un módulo del propio core de node con poner el nombre seria suficiente</li>\n</ul>\n<p>Si tenemos que usar la ruta específica puede que tengamos que poner una ruta larguisima, esto se puede evitar de varias formas usando la variable de entorno <strong>NODE PATH</strong> o a partir de la versión 2.0 de npm podríamos ponerlo en el fichero <strong>packaje.json</strong> (ya hablaremos de él). Si tenéis curiosidad sobre como serían estas formas navegar por el ciber-espacio que ya hay mucha literatura sobre esto.</p>\n<p>Antes de terminar este post hagamos un ejemplo creando nuestro propio módulo.<br>\nVamos a usar la carpeta <strong>node_modules</strong> que ya tenemos, y lo que hacemos es crear dentro un fichero js nuevo con nombre <strong>heroName.js</strong> y ponemos este código</p>\n<pre><code>'use strict';\n\nvar heroName = function(name){\n    console.log(&quot;Nuestro héroe es &quot;,name);\n}\n\nmodule.exports = heroName;\n</code></pre>\n<p>Y ahora fuera de la carpeta node_modules en nuestro proyecto creamos otro fichero js que yo lo he llamado <strong>modules.js</strong> y es tan simple como poner</p>\n<pre><code>'use strict';\n\nvar heroName = require('heroName');\n\nheroName(&quot;Dr.Manhattan&quot;)\n</code></pre>\n<p>Y listo, como véis es algo bastante simple y funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-21.57.14.png\" alt=\"Custom Module Example\"></p>\n<p>Tambiés es posible exportar más de un método u objeto, para ello cambiemos un poco el código de nuestro módulo</p>\n<pre><code>'use strict';\n\nvar heroName = function(name){\n    console.log(&quot;Nuestro héroe es &quot;,name);\n}\n\nvar powerLevel = function(power){\n    console.log(&quot;Power level es:&quot;,power);\n}\n\nmodule.exports = {\n    heroName: heroName,\n    powerLevel: powerLevel\n}\n</code></pre>\n<p>Y para usarlo, ahora nuestro require realmente devuelve un objeto con 2 métodos en él por lo que para usarlos</p>\n<pre><code>'use strict';\n\nvar hero = require('heroName');\n\nconsole.log(hero);\n\nhero.heroName(&quot;Dr.Manhattan&quot;);\n\nhero.powerLevel(&quot;9000&quot;);\n</code></pre>\n<p>He añadido un log de nuesto objeto <strong>hero</strong> para que veáis lo que contiene<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-22.05.12.png\" alt=\"Multiple exports module\"></p>\n<p>Si os fijáis ahora <strong>hero</strong> es un objeto con dos propiedades que realmente son dos funciones, las cuales podemos usar tranquilamente como si de cualquier otro método se tratara.</p>\n<h3 id=\"npm\">NPM</h3>\n<p>Son las siglas de <strong>Node Package Manager</strong>,y lo que nos permite es gestionar las dependencias de nuestra aplicación o proyecto, las instala, elimina o actualiza. Y también nos permite instalarlas de manera global para que podamos usarlas en cualquier proyecto.<br>\n<strong>NPM</strong> se apoya en un fichero llamado <strong>package.json</strong> que nos ayuda a mantener información de las dependencias de nuestro proyecto y las versiones que usamos.</p>\n<p>Si comenzamos con un proyecto nuevo lo primero que deberiamos hacer es ejecutar</p>\n<pre><code>npm init\n</code></pre>\n<p>Esto lo que haría sería crearnos un fichero <strong>package.json</strong> preguntandonos ciertas cosas sobre nuestro proyecto para luego almacenarlas en ese fichero<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.42.23.png\" alt=\"npm init example\"></p>\n<p>Tenemps algunas cosas útiles como por ejemplo la parte de <strong>scripts</strong> que vemos en el fichero. Lo que pongamos en esos scripts actuará como alias de algún comando que queramos ejecutar, por ejemplo podemos poner:</p>\n<pre><code>  &quot;scripts&quot;: {\n    &quot;test&quot;: &quot;node test.js&quot;,\n    &quot;start&quot;: &quot;node callbacks.js&quot;\n  },\n</code></pre>\n<p>Con esto solo tendríamos que poner <strong>npm</strong> seguido de nuestro nombre de script para ejecutarlo</p>\n<pre><code>npm start\n</code></pre>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.52.34.png\" alt=\"npm script test\"><br>\nComo vemos se ejecuta el fichero que ya creamos en algún post anterior. Puede que este caso no tenga mucha utilidad, pero si en lugar de ese comando tan simple tuvieramos que añadirle parámetros o queremos llamar a más elementos en la misma ejecución puede ser muy útil.</p>\n<p>Para gestionar las dependencias de Node y que se guarden en nuestro <strong>package.json</strong> solo tenemos que ejecutar el comando de instalación de npm seguido de <strong>--save</strong></p>\n<pre><code>npm install json --save\n</code></pre>\n<p>Ahora nuestro fichero package.json tendría esta pinta<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.56.54.png\" alt=\"New dependency example\"></p>\n<p>Vemos que nos ha añadido la <strong>dependencia json con su número de versión</strong>.</p>\n<p>También hemos comentado que podemos instalar dependencias de manera global en nuestro equipo, para ello con que ejecutemos</p>\n<pre><code>npm install -g jslint\n</code></pre>\n<p>Esto nos instalará en <strong>/usr/local/lib/node_modules/</strong> la dependencia y creará un acceso directo o enlace simbólico en <strong>/usr/local/bin</strong> para que podamos ejecutarla desde cualquier sitio si es necesario.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-13.01.32.png\" alt=\"Screen-Shot-2017-09-16-at-13.01.32\"></p>\n<p>Por último un detalle en cuanto las versiones de las dependencias, si os fijáis antes del número de versión pone un <strong>^</strong> y ¿por qué?....pues significa que npm puede actualizar esa dependencia siempre y cuando la versión no modifique el valor más a la izquierda que sea distinto de cero, es decir, si tenemos la versión</p>\n<pre><code>^9.0.6\n</code></pre>\n<p>El <strong>9</strong> no podría modificarlo, eso significa que la versión en este caso puede pasar de 9.0.7 a 9.X.X, pero si la versión que tenemos es</p>\n<pre><code>^0.2.5\n</code></pre>\n<p>Entonces la versión solo puede estar entre 0.2.5 a 0.2.X siendo X mayor que 5.</p>\n<p>En el próximo post empezaremos ya con express y el trabaj o propio de node.</p>\n<p>Un abrazooorrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-vi-modulos/","canonical_url":null,"uuid":"9460db52-032c-4b5b-9db3-ee9b5333a3ee","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59bc1cad6c31a60001f69f47","reading_time":6,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En este punto vamos a empezar con los módulos que son una parte muy importante y muy útil realmente.</p>\n<h2 id=\"queson\">Que son?</h2>\n<p>Bien los módulos básicamente son código JavaScript que utilizamos como si de una librería externa se tratase, es decir los importamos. Normalmente estos módulos se encuentran en una carpeta llamada <strong>node_modules</strong> en nuestro proyecto, que se crea automáticamente cuando instalamos algo con <strong>npm</strong>, por ejemplo. Pero claro no hemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la línea de comandos (con la posición o ubicación en el path de vuestro proyecto) y poner</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install async\n</code></pre></div>\n<p>Async es un módulo de npm que nos ayuda con la gestión de código asíncrono(como lo hace Node recordemos el event loop ;) ). De primeras al ejecutar el comando veréis algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-20.42.12.png\" alt=\"Npm example\"><br>\nDe momento no hagáis mucho caso a lo que pone ya entraremos en eso más adelante, lo que quería mostraros es que si miráis vuestra carpeta de proyecto os ha creado una nueva carpeta llamada <strong>node_modules</strong> y si miráis lo que hay dentro podréis ver que os ha descargado dos carpetas y estas a su vez tienen un montón de ficheros y carpetas no?....pues esto son módulos, prácticamente cada fichero <strong>js</strong> esta configurado como un módulo.</p>\n<p>Ahora que ya hemos visto un poco como es un módulo, hablemos un poco más en detalle de ellos.<br>\nEstán basados en el estándar <a href=\"http://requirejs.org/docs/commonjs.html\">CommonJS</a> y para usarlos tenemos que <strong>cargarlos</strong> en nuestros ficheros js, esto lo hacemos con la instrucción <strong>require</strong>.Esta instrucción es <strong>síncrona</strong>, es decir, no puede hacerse en un callback ni nada por el estilo.<br>\nAlgo bueno que tienen los módulos es que son <a href=\"http://www.oodesign.com/singleton-pattern.html\"><strong>singletons</strong></a>, que para el que no sepa que es, es un patrón de diseño con el cual nos aseguramos que solo tenemos una instancia de un objeto, como puede ser una conexion a una base de datos. Lo que hace es que la primera vez que ejecutamos el <strong>require</strong> se ejecuta el código necesario para crear una instancia nueva de nuestro módulo, el resto de veces que llamemos a <strong>require</strong> para el mismo módulo nos devolverá la misma instancia que se habia creado previamente.<br>\nPero, y como sabe lo que tiene que devolver al hacer el <strong>require</strong>?...Si miráis cualquier módulo veréis que al final tienen siempre algo parecido a esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">module.exports = nombreAlgunaFunciónUObjeto;\n</code></pre></div>\n<p>Eso es lo que realmente se importa, lo que está indicado en esa línea. Y para importar lo que haríamos sería</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var nombre = require ('nombreAlgunaFunciónUObjeto');\n</code></pre></div>\n<p>Con lo que quedaría almacenado en esa variable lo que se había exportado. Lo que contenga el <strong>require</strong> depende un poco de donde se encuentre el fichero o el script del cual queremos importar y de donde esté nuestra aplicación de Node. Como tal tenemos varias opciones</p>\n<ul>\n<li>Que esté en la carpeta <strong>node_modules</strong> local, es decir, la que nos ha creado en nuestro proyecto cuando hemos usado <strong>npm install</strong></li>\n<li>Puede encontrarse también en la carpeta <strong>node_modules</strong> global, ésta la crea npm al instalar node, y nosotros podemos almacenar módulos en ella usando <strong>npm install -g nombreMódulo</strong></li>\n<li>Si lo que ponemos empieza por './', '../' o similar lo buscará en la ruta que indiquemos partiendo de la nuestra (la del fichero donde usamos el require)</li>\n<li>Si es un módulo del propio core de node con poner el nombre seria suficiente</li>\n</ul>\n<p>Si tenemos que usar la ruta específica puede que tengamos que poner una ruta larguisima, esto se puede evitar de varias formas usando la variable de entorno <strong>NODE PATH</strong> o a partir de la versión 2.0 de npm podríamos ponerlo en el fichero <strong>packaje.json</strong> (ya hablaremos de él). Si tenéis curiosidad sobre como serían estas formas navegar por el ciber-espacio que ya hay mucha literatura sobre esto.</p>\n<p>Antes de terminar este post hagamos un ejemplo creando nuestro propio módulo.<br>\nVamos a usar la carpeta <strong>node_modules</strong> que ya tenemos, y lo que hacemos es crear dentro un fichero js nuevo con nombre <strong>heroName.js</strong> y ponemos este código</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 heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nmodule.exports = heroName;\n</code></pre></div>\n<p>Y ahora fuera de la carpeta node_modules en nuestro proyecto creamos otro fichero js que yo lo he llamado <strong>modules.js</strong> y es tan simple como poner</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 heroName = require('heroName');\n\nheroName(\"Dr.Manhattan\")\n</code></pre></div>\n<p>Y listo, como véis es algo bastante simple y funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-21.57.14.png\" alt=\"Custom Module Example\"></p>\n<p>Tambiés es posible exportar más de un método u objeto, para ello cambiemos un poco el código de nuestro módulo</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 heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nvar powerLevel = function(power){\n    console.log(\"Power level es:\",power);\n}\n\nmodule.exports = {\n    heroName: heroName,\n    powerLevel: powerLevel\n}\n</code></pre></div>\n<p>Y para usarlo, ahora nuestro require realmente devuelve un objeto con 2 métodos en él por lo que para usarlos</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 hero = require('heroName');\n\nconsole.log(hero);\n\nhero.heroName(\"Dr.Manhattan\");\n\nhero.powerLevel(\"9000\");\n</code></pre></div>\n<p>He añadido un log de nuesto objeto <strong>hero</strong> para que veáis lo que contiene<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-22.05.12.png\" alt=\"Multiple exports module\"></p>\n<p>Si os fijáis ahora <strong>hero</strong> es un objeto con dos propiedades que realmente son dos funciones, las cuales podemos usar tranquilamente como si de cualquier otro método se tratara.</p>\n<h3 id=\"npm\">NPM</h3>\n<p>Son las siglas de <strong>Node Package Manager</strong>,y lo que nos permite es gestionar las dependencias de nuestra aplicación o proyecto, las instala, elimina o actualiza. Y también nos permite instalarlas de manera global para que podamos usarlas en cualquier proyecto.<br>\n<strong>NPM</strong> se apoya en un fichero llamado <strong>package.json</strong> que nos ayuda a mantener información de las dependencias de nuestro proyecto y las versiones que usamos.</p>\n<p>Si comenzamos con un proyecto nuevo lo primero que deberiamos hacer es ejecutar</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm init\n</code></pre></div>\n<p>Esto lo que haría sería crearnos un fichero <strong>package.json</strong> preguntandonos ciertas cosas sobre nuestro proyecto para luego almacenarlas en ese fichero<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.42.23.png\" alt=\"npm init example\"></p>\n<p>Tenemps algunas cosas útiles como por ejemplo la parte de <strong>scripts</strong> que vemos en el fichero. Lo que pongamos en esos scripts actuará como alias de algún comando que queramos ejecutar, por ejemplo podemos poner:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">  \"scripts\": {\n    \"test\": \"node test.js\",\n    \"start\": \"node callbacks.js\"\n  },\n</code></pre></div>\n<p>Con esto solo tendríamos que poner <strong>npm</strong> seguido de nuestro nombre de script para ejecutarlo</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><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.52.34.png\" alt=\"npm script test\"><br>\nComo vemos se ejecuta el fichero que ya creamos en algún post anterior. Puede que este caso no tenga mucha utilidad, pero si en lugar de ese comando tan simple tuvieramos que añadirle parámetros o queremos llamar a más elementos en la misma ejecución puede ser muy útil.</p>\n<p>Para gestionar las dependencias de Node y que se guarden en nuestro <strong>package.json</strong> solo tenemos que ejecutar el comando de instalación de npm seguido de <strong>--save</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install json --save\n</code></pre></div>\n<p>Ahora nuestro fichero package.json tendría esta pinta<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.56.54.png\" alt=\"New dependency example\"></p>\n<p>Vemos que nos ha añadido la <strong>dependencia json con su número de versión</strong>.</p>\n<p>También hemos comentado que podemos instalar dependencias de manera global en nuestro equipo, para ello con que ejecutemos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install -g jslint\n</code></pre></div>\n<p>Esto nos instalará en <strong>/usr/local/lib/node_modules/</strong> la dependencia y creará un acceso directo o enlace simbólico en <strong>/usr/local/bin</strong> para que podamos ejecutarla desde cualquier sitio si es necesario.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-13.01.32.png\" alt=\"Screen-Shot-2017-09-16-at-13.01.32\"></p>\n<p>Por último un detalle en cuanto las versiones de las dependencias, si os fijáis antes del número de versión pone un <strong>^</strong> y ¿por qué?....pues significa que npm puede actualizar esa dependencia siempre y cuando la versión no modifique el valor más a la izquierda que sea distinto de cero, es decir, si tenemos la versión</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">^9.0.6\n</code></pre></div>\n<p>El <strong>9</strong> no podría modificarlo, eso significa que la versión en este caso puede pasar de 9.0.7 a 9.X.X, pero si la versión que tenemos es</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">^0.2.5\n</code></pre></div>\n<p>Entonces la versión solo puede estar entre 0.2.5 a 0.2.X siendo X mayor que 5.</p>\n<p>En el próximo post empezaremos ya con express y el trabaj o propio de node.</p>\n<p>Un abrazooorrrr</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 punto vamos a empezar con los módulos que son una parte muy importante y muy útil realmente."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{"id":"queson"},"children":[{"type":"text","value":"Que son?"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien los módulos básicamente son código JavaScript que utilizamos como si de una librería externa se tratase, es decir los importamos. Normalmente estos módulos se encuentran en una carpeta llamada "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node_modules"}]},{"type":"text","value":" en nuestro proyecto, que se crea automáticamente cuando instalamos algo con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":", por ejemplo. Pero claro no hemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la línea de comandos (con la posición o ubicación en el path de vuestro proyecto) y 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":"npm install async\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Async es un módulo de npm que nos ayuda con la gestión de código asíncrono(como lo hace Node recordemos el event loop ;) ). De primeras al ejecutar el comando veréis algo similar a esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-15-at-20.42.12.png","alt":"Npm example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nDe momento no hagáis mucho caso a lo que pone ya entraremos en eso más adelante, lo que quería mostraros es que si miráis vuestra carpeta de proyecto os ha creado una nueva carpeta llamada "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node_modules"}]},{"type":"text","value":" y si miráis lo que hay dentro podréis ver que os ha descargado dos carpetas y estas a su vez tienen un montón de ficheros y carpetas no?....pues esto son módulos, prácticamente cada fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"js"}]},{"type":"text","value":" esta configurado como un módulo."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora que ya hemos visto un poco como es un módulo, hablemos un poco más en detalle de ellos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEstán basados en el estándar "},{"type":"element","tagName":"a","properties":{"href":"http://requirejs.org/docs/commonjs.html"},"children":[{"type":"text","value":"CommonJS"}]},{"type":"text","value":" y para usarlos tenemos que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"cargarlos"}]},{"type":"text","value":" en nuestros ficheros js, esto lo hacemos con la instrucción "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"require"}]},{"type":"text","value":".Esta instrucción es "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"síncrona"}]},{"type":"text","value":", es decir, no puede hacerse en un callback ni nada por el estilo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAlgo bueno que tienen los módulos es que son "},{"type":"element","tagName":"a","properties":{"href":"http://www.oodesign.com/singleton-pattern.html"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"singletons"}]}]},{"type":"text","value":", que para el que no sepa que es, es un patrón de diseño con el cual nos aseguramos que solo tenemos una instancia de un objeto, como puede ser una conexion a una base de datos. Lo que hace es que la primera vez que ejecutamos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"require"}]},{"type":"text","value":" se ejecuta el código necesario para crear una instancia nueva de nuestro módulo, el resto de veces que llamemos a "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"require"}]},{"type":"text","value":" para el mismo módulo nos devolverá la misma instancia que se habia creado previamente."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPero, y como sabe lo que tiene que devolver al hacer el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"require"}]},{"type":"text","value":"?...Si miráis cualquier módulo veréis que al final tienen siempre algo parecido 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":"module.exports = nombreAlgunaFunciónUObjeto;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Eso es lo que realmente se importa, lo que está indicado en esa línea. Y para importar lo que haríamos 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":"var nombre = require ('nombreAlgunaFunciónUObjeto');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con lo que quedaría almacenado en esa variable lo que se había exportado. Lo que contenga el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"require"}]},{"type":"text","value":" depende un poco de donde se encuentre el fichero o el script del cual queremos importar y de donde esté nuestra aplicación de Node. Como tal tenemos varias opciones"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Que esté en la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node_modules"}]},{"type":"text","value":" local, es decir, la que nos ha creado en nuestro proyecto cuando hemos usado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm install"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Puede encontrarse también en la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node_modules"}]},{"type":"text","value":" global, ésta la crea npm al instalar node, y nosotros podemos almacenar módulos en ella usando "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm install -g nombreMódulo"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Si lo que ponemos empieza por './', '../' o similar lo buscará en la ruta que indiquemos partiendo de la nuestra (la del fichero donde usamos el require)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Si es un módulo del propio core de node con poner el nombre seria suficiente"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si tenemos que usar la ruta específica puede que tengamos que poner una ruta larguisima, esto se puede evitar de varias formas usando la variable de entorno "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NODE PATH"}]},{"type":"text","value":" o a partir de la versión 2.0 de npm podríamos ponerlo en el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"packaje.json"}]},{"type":"text","value":" (ya hablaremos de él). Si tenéis curiosidad sobre como serían estas formas navegar por el ciber-espacio que ya hay mucha literatura sobre esto."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Antes de terminar este post hagamos un ejemplo creando nuestro propio módulo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a usar la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node_modules"}]},{"type":"text","value":" que ya tenemos, y lo que hacemos es crear dentro un fichero js nuevo con nombre "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"heroName.js"}]},{"type":"text","value":" y ponemos este código"}]},{"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 heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nmodule.exports = heroName;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y ahora fuera de la carpeta node_modules en nuestro proyecto creamos otro fichero js que yo lo he llamado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"modules.js"}]},{"type":"text","value":" y es tan simple como 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":"'use strict';\n\nvar heroName = require('heroName');\n\nheroName(\"Dr.Manhattan\")\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y listo, como véis es algo bastante simple y funciona"},{"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-15-at-21.57.14.png","alt":"Custom Module Example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tambiés es posible exportar más de un método u objeto, para ello cambiemos un poco el código de nuestro módulo"}]},{"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 heroName = function(name){\n    console.log(\"Nuestro héroe es \",name);\n}\n\nvar powerLevel = function(power){\n    console.log(\"Power level es:\",power);\n}\n\nmodule.exports = {\n    heroName: heroName,\n    powerLevel: powerLevel\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y para usarlo, ahora nuestro require realmente devuelve un objeto con 2 métodos en él por lo que para usarlos"}]},{"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 hero = require('heroName');\n\nconsole.log(hero);\n\nhero.heroName(\"Dr.Manhattan\");\n\nhero.powerLevel(\"9000\");\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"He añadido un log de nuesto objeto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" para que veáis lo que contiene"},{"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-15-at-22.05.12.png","alt":"Multiple exports module"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis ahora "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" es un objeto con dos propiedades que realmente son dos funciones, las cuales podemos usar tranquilamente como si de cualquier otro método se tratara."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"npm"},"children":[{"type":"text","value":"NPM"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Son las siglas de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Node Package Manager"}]},{"type":"text","value":",y lo que nos permite es gestionar las dependencias de nuestra aplicación o proyecto, las instala, elimina o actualiza. Y también nos permite instalarlas de manera global para que podamos usarlas en cualquier proyecto."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NPM"}]},{"type":"text","value":" se apoya en un fichero llamado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" que nos ayuda a mantener información de las dependencias de nuestro proyecto y las versiones que usamos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si comenzamos con un proyecto nuevo lo primero que deberiamos hacer es ejecutar"}]},{"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 init\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto lo que haría sería crearnos un fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" preguntandonos ciertas cosas sobre nuestro proyecto para luego almacenarlas en ese fichero"},{"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-16-at-12.42.23.png","alt":"npm init example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tenemps algunas cosas útiles como por ejemplo la parte de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"scripts"}]},{"type":"text","value":" que vemos en el fichero. Lo que pongamos en esos scripts actuará como alias de algún comando que queramos ejecutar, por ejemplo 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":"  \"scripts\": {\n    \"test\": \"node test.js\",\n    \"start\": \"node callbacks.js\"\n  },\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con esto solo tendríamos que poner "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":" seguido de nuestro nombre de script para ejecutarlo"}]},{"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":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.52.34.png","alt":"npm script test"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo vemos se ejecuta el fichero que ya creamos en algún post anterior. Puede que este caso no tenga mucha utilidad, pero si en lugar de ese comando tan simple tuvieramos que añadirle parámetros o queremos llamar a más elementos en la misma ejecución puede ser muy útil."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para gestionar las dependencias de Node y que se guarden en nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"package.json"}]},{"type":"text","value":" solo tenemos que ejecutar el comando de instalación de npm seguido de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"--save"}]}]},{"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 json --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora nuestro fichero package.json tendría esta pinta"},{"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-16-at-12.56.54.png","alt":"New dependency example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Vemos que nos ha añadido la "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"dependencia json con su número de versión"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"También hemos comentado que podemos instalar dependencias de manera global en nuestro equipo, para ello con que ejecutemos"}]},{"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 -g jslint\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos instalará en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"/usr/local/lib/node_modules/"}]},{"type":"text","value":" la dependencia y creará un acceso directo o enlace simbólico en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"/usr/local/bin"}]},{"type":"text","value":" para que podamos ejecutarla desde cualquier sitio si es necesario."},{"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-16-at-13.01.32.png","alt":"Screen-Shot-2017-09-16-at-13.01.32"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Por último un detalle en cuanto las versiones de las dependencias, si os fijáis antes del número de versión pone un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"^"}]},{"type":"text","value":" y ¿por qué?....pues significa que npm puede actualizar esa dependencia siempre y cuando la versión no modifique el valor más a la izquierda que sea distinto de cero, es decir, si tenemos la versión"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"^9.0.6\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"El "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"9"}]},{"type":"text","value":" no podría modificarlo, eso significa que la versión en este caso puede pasar de 9.0.7 a 9.X.X, pero si la versión que tenemos es"}]},{"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":"^0.2.5\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Entonces la versión solo puede estar entre 0.2.5 a 0.2.X siendo X mayor que 5."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En el próximo post empezaremos ya con express y el trabaj o propio de node."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un abrazooorrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"queson","heading":"Que son?","items":[{"id":"npm","heading":"NPM"}]}]},"featureImageSharp":{"base":"nodebaner-2.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-2.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-2.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-2.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-2.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-2.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-2.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-2.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-2.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-2.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-2.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-2.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-2.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-2.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-2.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-2.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"next":{"id":"Ghost__Post__5a338158333e0f134c248f2a","title":"React Superhero (V): Mobx","slug":"react-superhero-v-mobx","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Captain-Atom-1.jpg","excerpt":"En este post hablaremos de una librería muy útil llamada Mobx que entre otras\ncosas nos facilita un poco el desarrollo en cuanto a la comunicación entre\ncomponentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un\ncomponente a otro para realizar alguna modificación en alguna propiedad, pues\nbien Mobx nos facilita este planteamiento (entre otras cosas claro ;) ). Si\nqueréis algo más de información aqui tenéis la página oficial de Mobx\n[https://mobx.js.org/]\n\nInstalación\nPara i","custom_excerpt":null,"visibility":"public","created_at_pretty":"6 Sep 2017","published_at_pretty":"12 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-06T21:51:25.000+02:00","published_at":"2017-09-12T10:09:00.000+02:00","updated_at":"2018-01-22T09:48:46.000+01:00","meta_title":null,"meta_description":"Veremos una librería muy útil que se usa mucho en React. Esta librería nos facilita la comunicación entre componentes.","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":"reactjs","url":"https://jlgarcia.fulldev.ninja/tag/reactjs/","name":"reactjs","visibility":"public","feature_image":null,"description":null,"meta_title":"ReactJS Ninjas","meta_description":"Aprenderemos a usar esta estupenda librería que nos permite desarrollar con un estilo basado en componentes y centrándonse en tener los datos sincronizados","featureImageSharp":null},"tags":[{"slug":"reactjs","url":"https://jlgarcia.fulldev.ninja/tag/reactjs/","name":"reactjs","visibility":"public","feature_image":null,"description":null,"meta_title":"ReactJS Ninjas","meta_description":"Aprenderemos a usar esta estupenda librería que nos permite desarrollar con un estilo basado en componentes y centrándonse en tener los datos sincronizados","featureImageSharp":null}],"plaintext":"En este post hablaremos de una librería muy útil llamada Mobx que entre otras\ncosas nos facilita un poco el desarrollo en cuanto a la comunicación entre\ncomponentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un\ncomponente a otro para realizar alguna modificación en alguna propiedad, pues\nbien Mobx nos facilita este planteamiento (entre otras cosas claro ;) ). Si\nqueréis algo más de información aqui tenéis la página oficial de Mobx\n[https://mobx.js.org/]\n\nInstalación\nPara instalar mobx usaremos nuestro magnífico npm:\n\nnpm install mobx mobx-react --save\n\n\nEsto nos instalará en el proyecto los módulos de NodeJS necesarios para poder\ntrabajar con Mobx\n\nUsando Mobx\nBien vamos a empezar a partir de la estructura de proyecto que teniamos en el\npost anterior (tras ejecutar nuestro create-app....).\nVamos a trabajar sobre el fichero App.js que es el componente que se esta\nrendeando por defecto, pero vamos a cambiarlo un poco y asi vemos que realmente\nestamos en este punto, vamos a cambiar la frase que aparece debajo de Welcome to\nReact para indicar que trabajaremos despues de esa linea:\n\nimport React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n      </div>\n    );\n  }\n}\n\nexport default App;\n\n\nTras guardar, automáticamente tendriamos algo similar a\n\nBien ya sabemos donde estamos, ahora haremos un ejemplo simple para ver que es\nlo que conseguimos con Mobx, vamos a mostrar un número y este aumentará cuando\npulsemos un botón.\nPrimero mostremos nuestro número, en un principio es algo sencillo que ya hemos\nvisto no?, creamos un componente nuevo y lo indicamos en el componente que se\nesta renderizando como principal no??...... si esa es una opción pero al final\nestaríamos haciendo lo mismo que ya hemos visto y entonces para que queremos \nmobx no??. Pues bien la teoría del componente es válida a medias, vamos a crear\nuna clase y en esta tenemos que importar extendObservable de la librería de mobx\n. Yo le he puesto el nombre FirstMobxClass.js y esto es lo que ponemos\n\nimport {extendObservable} from 'mobx'\n\nclass FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        })\n    }\n}\n\n//Creamos una nueva instancia de nuestra clase,la almacenamos\n// y la exportamos para que se tenga acceso desde fuera\n//de esta clase\nvar numberMobxClass = new FirstMobxClass();\n\nexport default numberMobxClass;\n\n\nCon esto tendríamos una variable con una propiedad number que deberíamos poder\nusar. Para ello volvamos a nuestra clase App.js y ponemos lo siguiente:\n\nimport React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n        <h2>{ numberMobxClass.number }</h2>\n      </div>\n    );\n  }\n}\n\nexport default App;\n\n\nPara diferenciar los imports que ya teniamos de los nuevos he indicado el\ncomentario our imports. Como véis lo que importamos es nuestra variable del\nfichero con nombre FirstMobxClass y para usarlo nos valemos de las magias del\nlenguaje JSX y con poner\n\n<h2>{ numberMobxClass.number }</h2>\n\n\nYa tendríamos nuestra linea con el número que hemos puesto\n\n\nLo siguiente será crear nuestro botón, en este caso seguimos la teoría inicial\nde los componentes que ya sabíamos, me refiero a que lo creamos como un\ncomponente normal. Creamos el fichero IncreaseNumber.js\n\nimport React, { Component } from 'react';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        <button>Increase Number</button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n\n\nDe momento nada nuevo, para verlo lo importamos en App.js y lo ponemos a\ncontinuación, es decir ahora en App.js debajo de Our imports añadimos un import\nmás debajo del numberMobxClass\n\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\n\n\nY luego debajo de nuestro número le ponemos el botón\n\n<h2>{ numberMobxClass.number }</h2>\n<IncreaseNumber/>\n\n\nY al guardar ya veríamos nuestro botón\n\nPero aunque pulsemos de momento no hace nada no??....continuemos ahora para\nañadirle funcionalidad. Al igual que haciamos antes necesitamos un método que\nhaga que aumente nuestro número, y al igual que haciamos antes lo mejor es que\nlo creemos en el mismo punto que donde tenemos nuestra propiedad. Esto es tan\nsimple como sumarle 1 al número, es decir añadimos a nuestra clase \nFirstMobxClass el método increase\n\nclass FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        });\n    }\n    increase(){\n        this.number = this.number + 1;\n    }\n}\n\n\nYa tenemos nuestro método ahora indiquemosle a nuestro botón que tiene que\nusarlo, probemos a ponerlo directamente con un onClick en el componente \nIncreaseNumber\n\nimport React, { Component } from 'react';\nimport numberMobxClass from './FirstMobxClass';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        <button onClick={numberMobxClass.increase} >Increase Number</button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n\n\nSi os fijáis hemos importado nuestra clase numberMobxClass y hemos usado nuestro\nmétodo increase directamente en el onClick, bien si guardamos vemos que la\npágina renderiza bien pero que pasa si pulsamos.......UPSSS!!!\n\nVemos que nos sale este error, y eso es como os podéis imaginar que this no\ntiene nada, diréis \"pues entonces podemos ponerle un bind igual que haciamos\nantes y ya esta\", bueno pues vamos a probarlo a ver que pasa y de paso le\nponemos al método increase un log para ver que tiene this.\nEl método increase ahora quedaria así\n\nincrease(){\n    console.log(this);\n    this.number = this.number + 1;\n}\n\n\nY nuestro onClick\n\n<button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>\n\n\nVeamos que pasa cuando pulsamos\n\nNo nos da error pero si nos fijamos en lo que nos devuelve nuestro log, la\npropiedad number es NaN y eso ¿por qué? Pues porque realmente estamos pasando\ncon bind el this de nuestro componente IncreaseNumber el cual no tiene esa\npropiedad, hagamos un pequeño ejemplo para verlo, creemos una propiedad en el\ncomponente IncreaseNumber como hemos visto en anteriores post y veamos el log\nahora.\nEl componente IncreaseNumber quedaria asi\n\nclass IncreaseNumber extends Component {\n    constructor(){\n        super();\n        this.test = 2;\n        \n    }\n    render(){\n        return(\n        <button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>\n        )\n    }\n}\n\n\nY al pulsar tenemos este log\n\nSi os fijáis number sigue siendo NaN pero sin embargo tenemos nuestra propiedad \ntest con el valor que hemos puesto, entonces quiere decir que estamos pasando el \ncontexto del componente IncreaseNumber.... y entonces como lo hacemos??...Es más\nfácil de lo que parece, onClick espera una función no?, pues simplemente usemos\nuna función que cada vez que se use esta \"llame\" a nuestro método increase (al\nestilo típico de la programación habitual)\nCon esta teoría nuestro onClick quedaría así\n\n<button onClick={() => numberMobxClass.increase()} >Increase Number</button>\n\n\nVeamos lo que tiene this ahora\n\nAnda!! Ahora nuestro number si aumenta pero..... en nuestra página no se\nve.....y eso?? bueno la explicación es sencilla no estamos \"observando\" la\npropiedad para que responda los cambios y como hacemos eso?...Fácil, importamos \nobserver de la libreria mobx-react y le indicamos que observe donde estamos\nrenderizando, es decir en App.js, por lo que el componente quedaría asi\n\nimport React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\nimport { observer } from 'mobx-react';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n        <h2>{ numberMobxClass.number }</h2>\n        <IncreaseNumber/>\n      </div>\n    );\n  }\n}\n\nexport default observer(App);\n\n\nY voilá ya tenemos nuestro numero aumentando en nuestra página\n\n\nEspero que quede más o menos claro como estamos usando la característica \nobservable que nos proporciona Mobx, que realmente nos facilita un poco estar\npendiente de los estados o cambios de nuestras propiedades.\n\nEn el siguiente post seguiremos viendo que más cosas podemos hacer con Mobx, nos\nvemos, un abrazooorrrrrr","html":"<!--kg-card-begin: markdown--><p>En este post hablaremos de una librería muy útil llamada <strong>Mobx</strong> que entre otras cosas nos facilita un poco el desarrollo en cuanto a la comunicación entre componentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un componente a otro para realizar alguna modificación en alguna propiedad, pues bien <strong>Mobx</strong> nos facilita este planteamiento (entre otras cosas claro ;) ). Si queréis algo más de información aqui tenéis la página oficial de <a href=\"https://mobx.js.org/\">Mobx</a></p>\n<h3 id=\"instalacin\">Instalación</h3>\n<p>Para instalar <strong>mobx</strong> usaremos nuestro magnífico <strong>npm</strong>:</p>\n<pre><code>npm install mobx mobx-react --save\n</code></pre>\n<p>Esto nos instalará en el proyecto los módulos de NodeJS necesarios para poder trabajar con <strong>Mobx</strong></p>\n<h3 id=\"usandomobx\">Usando Mobx</h3>\n<p>Bien vamos a empezar a partir de la estructura de proyecto que teniamos en el post anterior (tras ejecutar nuestro create-app....).<br>\nVamos a trabajar sobre el fichero <strong>App.js</strong> que es el componente que se esta rendeando por defecto, pero vamos a cambiarlo un poco y asi vemos que realmente estamos en este punto, vamos a cambiar la frase que aparece debajo de <strong>Welcome to React</strong> para indicar que trabajaremos despues de esa linea:</p>\n<pre><code>import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n\nclass App extends Component {\n  render() {\n    return (\n      &lt;div className=&quot;App&quot;&gt;\n        &lt;div className=&quot;App-header&quot;&gt;\n          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;\n          &lt;h2&gt;Welcome to React&lt;/h2&gt;\n        &lt;/div&gt;\n        &lt;p className=&quot;App-intro&quot;&gt;\n         We started working below this line\n        &lt;/p&gt;\n      &lt;/div&gt;\n    );\n  }\n}\n\nexport default App;\n</code></pre>\n<p>Tras guardar, automáticamente tendriamos algo similar a<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-13.37.40.png\" alt=\"Started working\"><br>\nBien ya sabemos donde estamos, ahora haremos un ejemplo simple para ver que es lo que conseguimos con <strong>Mobx</strong>, vamos a mostrar un número y este aumentará cuando pulsemos un botón.<br>\nPrimero mostremos nuestro número, en un principio es algo sencillo que ya hemos visto no?, creamos un componente nuevo y lo indicamos en el componente que se esta renderizando como principal no??...... si esa es una opción pero al final estaríamos haciendo lo mismo que ya hemos visto y entonces para que queremos <strong>mobx</strong> no??. Pues bien la teoría del componente es válida a medias, vamos a crear una clase y en esta tenemos que importar <strong>extendObservable</strong> de la librería de <strong>mobx</strong>. Yo le he puesto el nombre <strong>FirstMobxClass.js</strong> y esto es lo que ponemos</p>\n<pre><code>import {extendObservable} from 'mobx'\n\nclass FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        })\n    }\n}\n\n//Creamos una nueva instancia de nuestra clase,la almacenamos\n// y la exportamos para que se tenga acceso desde fuera\n//de esta clase\nvar numberMobxClass = new FirstMobxClass();\n\nexport default numberMobxClass;\n</code></pre>\n<p>Con esto tendríamos una variable con una propiedad number que deberíamos poder usar. Para ello volvamos a nuestra clase App.js y ponemos lo siguiente:</p>\n<pre><code>import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\n\nclass App extends Component {\n  render() {\n    return (\n      &lt;div className=&quot;App&quot;&gt;\n        &lt;div className=&quot;App-header&quot;&gt;\n          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;\n          &lt;h2&gt;Welcome to React&lt;/h2&gt;\n        &lt;/div&gt;\n        &lt;p className=&quot;App-intro&quot;&gt;\n         We started working below this line\n        &lt;/p&gt;\n        &lt;h2&gt;{ numberMobxClass.number }&lt;/h2&gt;\n      &lt;/div&gt;\n    );\n  }\n}\n\nexport default App;\n</code></pre>\n<p>Para diferenciar los imports que ya teniamos de los nuevos he indicado el comentario <strong>our imports</strong>. Como véis lo que importamos es nuestra variable del fichero con nombre <strong>FirstMobxClass</strong> y para usarlo nos valemos de las magias del lenguaje <strong>JSX</strong> y con poner</p>\n<pre><code>&lt;h2&gt;{ numberMobxClass.number }&lt;/h2&gt;\n</code></pre>\n<p>Ya tendríamos nuestra linea con el número que hemos puesto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.01.56.png\" alt=\"FirstMobx\"></p>\n<p>Lo siguiente será crear nuestro botón, en este caso seguimos la teoría inicial de los componentes que ya sabíamos, me refiero a que lo creamos como un componente normal. Creamos el fichero <strong>IncreaseNumber.js</strong></p>\n<pre><code>import React, { Component } from 'react';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        &lt;button&gt;Increase Number&lt;/button&gt;\n        )\n    }\n}\n\nexport default IncreaseNumber;\n</code></pre>\n<p>De momento nada nuevo, para verlo lo importamos en <strong>App.js</strong> y lo ponemos a continuación, es decir ahora en App.js debajo de <strong>Our imports</strong> añadimos un import más debajo del <strong>numberMobxClass</strong></p>\n<pre><code>//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\n</code></pre>\n<p>Y luego debajo de nuestro número le ponemos el botón</p>\n<pre><code>&lt;h2&gt;{ numberMobxClass.number }&lt;/h2&gt;\n&lt;IncreaseNumber/&gt;\n</code></pre>\n<p>Y al guardar ya veríamos nuestro botón<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.12.23.png\" alt=\"NewButton\"><br>\nPero aunque pulsemos de momento no hace nada no??....continuemos ahora para añadirle funcionalidad. Al igual que haciamos antes necesitamos un método que haga que aumente nuestro número, y al igual que haciamos antes lo mejor es que lo creemos en el mismo punto que donde tenemos nuestra propiedad. Esto es tan simple como sumarle 1 al número, es decir añadimos a nuestra clase <strong>FirstMobxClass</strong> el método <strong>increase</strong></p>\n<pre><code>class FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        });\n    }\n    increase(){\n        this.number = this.number + 1;\n    }\n}\n</code></pre>\n<p>Ya tenemos nuestro método ahora indiquemosle a nuestro botón que tiene que usarlo, probemos a ponerlo directamente con un <strong>onClick</strong> en el componente <strong>IncreaseNumber</strong></p>\n<pre><code>import React, { Component } from 'react';\nimport numberMobxClass from './FirstMobxClass';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        &lt;button onClick={numberMobxClass.increase} &gt;Increase Number&lt;/button&gt;\n        )\n    }\n}\n\nexport default IncreaseNumber;\n</code></pre>\n<p>Si os fijáis hemos importado nuestra clase <strong>numberMobxClass</strong> y hemos usado nuestro método <strong>increase</strong> directamente en el <strong>onClick</strong>, bien si guardamos vemos que la página renderiza bien pero que pasa si pulsamos.......UPSSS!!!<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.33.03.png\" alt=\"Error this==null\"><br>\nVemos que nos sale este error, y eso es  como os podéis imaginar que <strong>this</strong> no tiene nada, diréis &quot;pues entonces podemos ponerle un <strong>bind</strong> igual que haciamos antes y ya esta&quot;, bueno pues vamos a probarlo a ver que pasa y de paso le ponemos al método <strong>increase</strong> un log para ver que tiene <strong>this</strong>.<br>\nEl método <strong>increase</strong> ahora quedaria así</p>\n<pre><code>increase(){\n    console.log(this);\n    this.number = this.number + 1;\n}\n</code></pre>\n<p>Y nuestro <strong>onClick</strong></p>\n<pre><code>&lt;button onClick={numberMobxClass.increase.bind(this)} &gt;Increase Number&lt;/button&gt;\n</code></pre>\n<p>Veamos que pasa cuando pulsamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.37.48.png\" alt=\"Log with this\"><br>\nNo nos da error pero si nos fijamos en lo que nos devuelve nuestro log, la propiedad <strong>number</strong> es <strong>NaN</strong> y eso ¿por qué? Pues porque realmente estamos pasando con <strong>bind</strong> el <strong>this</strong> de nuestro componente <strong>IncreaseNumber</strong> el cual no tiene esa propiedad, hagamos un pequeño ejemplo para verlo, creemos una propiedad en el componente <strong>IncreaseNumber</strong> como hemos visto en anteriores post y veamos el log ahora.<br>\nEl componente <strong>IncreaseNumber</strong> quedaria asi</p>\n<pre><code>class IncreaseNumber extends Component {\n    constructor(){\n        super();\n        this.test = 2;\n        \n    }\n    render(){\n        return(\n        &lt;button onClick={numberMobxClass.increase.bind(this)} &gt;Increase Number&lt;/button&gt;\n        )\n    }\n}\n</code></pre>\n<p>Y al pulsar tenemos este log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.47.11.png\" alt=\"Testing this context\"><br>\nSi os fijáis <strong>number</strong> sigue siendo <strong>NaN</strong> pero sin embargo tenemos nuestra propiedad <strong>test</strong> con el valor que hemos puesto, entonces quiere decir que estamos pasando el <strong>contexto</strong> del componente <strong>IncreaseNumber</strong>.... y entonces como lo hacemos??...Es más fácil de lo que parece, <strong>onClick</strong> espera una función no?, pues simplemente usemos una función que cada vez que se use esta &quot;llame&quot; a nuestro método <strong>increase</strong> (al estilo típico de la programación habitual)<br>\nCon esta teoría nuestro <strong>onClick</strong> quedaría así</p>\n<pre><code>&lt;button onClick={() =&gt; numberMobxClass.increase()} &gt;Increase Number&lt;/button&gt;\n</code></pre>\n<p>Veamos lo que tiene <strong>this</strong> ahora<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.52.52.png\" alt=\"Log with number increase\"><br>\nAnda!! Ahora nuestro <strong>number</strong> si aumenta pero..... en nuestra página no se ve.....y eso?? bueno la explicación es sencilla no estamos <strong>&quot;observando&quot;</strong> la propiedad para que responda los cambios y como hacemos eso?...Fácil, importamos <strong>observer</strong> de la libreria <strong>mobx-react</strong> y le indicamos que observe donde estamos renderizando, es decir en <strong>App.js</strong>, por lo que el componente quedaría asi</p>\n<pre><code>import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\nimport { observer } from 'mobx-react';\n\nclass App extends Component {\n  render() {\n    return (\n      &lt;div className=&quot;App&quot;&gt;\n        &lt;div className=&quot;App-header&quot;&gt;\n          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;\n          &lt;h2&gt;Welcome to React&lt;/h2&gt;\n        &lt;/div&gt;\n        &lt;p className=&quot;App-intro&quot;&gt;\n         We started working below this line\n        &lt;/p&gt;\n        &lt;h2&gt;{ numberMobxClass.number }&lt;/h2&gt;\n        &lt;IncreaseNumber/&gt;\n      &lt;/div&gt;\n    );\n  }\n}\n\nexport default observer(App);\n</code></pre>\n<p>Y voilá ya tenemos nuestro numero aumentando en nuestra página<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-15.00.31.png\" alt=\"The meaning of life\"></p>\n<p>Espero que quede más o menos claro como estamos usando la característica <strong>observable</strong> que nos proporciona <strong>Mobx</strong>, que realmente nos facilita un poco estar pendiente de los estados o cambios de nuestras propiedades.</p>\n<p>En el siguiente post seguiremos viendo que más cosas podemos hacer con <strong>Mobx</strong>, nos vemos, un abrazooorrrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/react-superhero-v-mobx/","canonical_url":null,"uuid":"93502e4c-0ee1-43cb-a96d-cb6751f8ee84","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59b051bd6c31a60001f69f0d","reading_time":7,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En este post hablaremos de una librería muy útil llamada <strong>Mobx</strong> que entre otras cosas nos facilita un poco el desarrollo en cuanto a la comunicación entre componentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un componente a otro para realizar alguna modificación en alguna propiedad, pues bien <strong>Mobx</strong> nos facilita este planteamiento (entre otras cosas claro ;) ). Si queréis algo más de información aqui tenéis la página oficial de <a href=\"https://mobx.js.org/\">Mobx</a></p>\n<h3 id=\"instalacin\">Instalación</h3>\n<p>Para instalar <strong>mobx</strong> usaremos nuestro magnífico <strong>npm</strong>:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install mobx mobx-react --save\n</code></pre></div>\n<p>Esto nos instalará en el proyecto los módulos de NodeJS necesarios para poder trabajar con <strong>Mobx</strong></p>\n<h3 id=\"usandomobx\">Usando Mobx</h3>\n<p>Bien vamos a empezar a partir de la estructura de proyecto que teniamos en el post anterior (tras ejecutar nuestro create-app....).<br>\nVamos a trabajar sobre el fichero <strong>App.js</strong> que es el componente que se esta rendeando por defecto, pero vamos a cambiarlo un poco y asi vemos que realmente estamos en este punto, vamos a cambiar la frase que aparece debajo de <strong>Welcome to React</strong> para indicar que trabajaremos despues de esa linea:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n\nclass App extends Component {\n  render() {\n    return (\n      &#x3C;div className=\"App\">\n        &#x3C;div className=\"App-header\">\n          &#x3C;img src={logo} className=\"App-logo\" alt=\"logo\" />\n          &#x3C;h2>Welcome to React&#x3C;/h2>\n        &#x3C;/div>\n        &#x3C;p className=\"App-intro\">\n         We started working below this line\n        &#x3C;/p>\n      &#x3C;/div>\n    );\n  }\n}\n\nexport default App;\n</code></pre></div>\n<p>Tras guardar, automáticamente tendriamos algo similar a<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-13.37.40.png\" alt=\"Started working\"><br>\nBien ya sabemos donde estamos, ahora haremos un ejemplo simple para ver que es lo que conseguimos con <strong>Mobx</strong>, vamos a mostrar un número y este aumentará cuando pulsemos un botón.<br>\nPrimero mostremos nuestro número, en un principio es algo sencillo que ya hemos visto no?, creamos un componente nuevo y lo indicamos en el componente que se esta renderizando como principal no??...... si esa es una opción pero al final estaríamos haciendo lo mismo que ya hemos visto y entonces para que queremos <strong>mobx</strong> no??. Pues bien la teoría del componente es válida a medias, vamos a crear una clase y en esta tenemos que importar <strong>extendObservable</strong> de la librería de <strong>mobx</strong>. Yo le he puesto el nombre <strong>FirstMobxClass.js</strong> y esto es lo que ponemos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import {extendObservable} from 'mobx'\n\nclass FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        })\n    }\n}\n\n//Creamos una nueva instancia de nuestra clase,la almacenamos\n// y la exportamos para que se tenga acceso desde fuera\n//de esta clase\nvar numberMobxClass = new FirstMobxClass();\n\nexport default numberMobxClass;\n</code></pre></div>\n<p>Con esto tendríamos una variable con una propiedad number que deberíamos poder usar. Para ello volvamos a nuestra clase App.js 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\">import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\n\nclass App extends Component {\n  render() {\n    return (\n      &#x3C;div className=\"App\">\n        &#x3C;div className=\"App-header\">\n          &#x3C;img src={logo} className=\"App-logo\" alt=\"logo\" />\n          &#x3C;h2>Welcome to React&#x3C;/h2>\n        &#x3C;/div>\n        &#x3C;p className=\"App-intro\">\n         We started working below this line\n        &#x3C;/p>\n        &#x3C;h2>{ numberMobxClass.number }&#x3C;/h2>\n      &#x3C;/div>\n    );\n  }\n}\n\nexport default App;\n</code></pre></div>\n<p>Para diferenciar los imports que ya teniamos de los nuevos he indicado el comentario <strong>our imports</strong>. Como véis lo que importamos es nuestra variable del fichero con nombre <strong>FirstMobxClass</strong> y para usarlo nos valemos de las magias del lenguaje <strong>JSX</strong> y con poner</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;h2>{ numberMobxClass.number }&#x3C;/h2>\n</code></pre></div>\n<p>Ya tendríamos nuestra linea con el número que hemos puesto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.01.56.png\" alt=\"FirstMobx\"></p>\n<p>Lo siguiente será crear nuestro botón, en este caso seguimos la teoría inicial de los componentes que ya sabíamos, me refiero a que lo creamos como un componente normal. Creamos el fichero <strong>IncreaseNumber.js</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import React, { Component } from 'react';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        &#x3C;button>Increase Number&#x3C;/button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n</code></pre></div>\n<p>De momento nada nuevo, para verlo lo importamos en <strong>App.js</strong> y lo ponemos a continuación, es decir ahora en App.js debajo de <strong>Our imports</strong> añadimos un import más debajo del <strong>numberMobxClass</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\n</code></pre></div>\n<p>Y luego debajo de nuestro número le ponemos el botón</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;h2>{ numberMobxClass.number }&#x3C;/h2>\n&#x3C;IncreaseNumber/>\n</code></pre></div>\n<p>Y al guardar ya veríamos nuestro botón<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.12.23.png\" alt=\"NewButton\"><br>\nPero aunque pulsemos de momento no hace nada no??....continuemos ahora para añadirle funcionalidad. Al igual que haciamos antes necesitamos un método que haga que aumente nuestro número, y al igual que haciamos antes lo mejor es que lo creemos en el mismo punto que donde tenemos nuestra propiedad. Esto es tan simple como sumarle 1 al número, es decir añadimos a nuestra clase <strong>FirstMobxClass</strong> el método <strong>increase</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">class FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        });\n    }\n    increase(){\n        this.number = this.number + 1;\n    }\n}\n</code></pre></div>\n<p>Ya tenemos nuestro método ahora indiquemosle a nuestro botón que tiene que usarlo, probemos a ponerlo directamente con un <strong>onClick</strong> en el componente <strong>IncreaseNumber</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import React, { Component } from 'react';\nimport numberMobxClass from './FirstMobxClass';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        &#x3C;button onClick={numberMobxClass.increase} >Increase Number&#x3C;/button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n</code></pre></div>\n<p>Si os fijáis hemos importado nuestra clase <strong>numberMobxClass</strong> y hemos usado nuestro método <strong>increase</strong> directamente en el <strong>onClick</strong>, bien si guardamos vemos que la página renderiza bien pero que pasa si pulsamos.......UPSSS!!!<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.33.03.png\" alt=\"Error this==null\"><br>\nVemos que nos sale este error, y eso es  como os podéis imaginar que <strong>this</strong> no tiene nada, diréis \"pues entonces podemos ponerle un <strong>bind</strong> igual que haciamos antes y ya esta\", bueno pues vamos a probarlo a ver que pasa y de paso le ponemos al método <strong>increase</strong> un log para ver que tiene <strong>this</strong>.<br>\nEl método <strong>increase</strong> ahora quedaria así</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">increase(){\n    console.log(this);\n    this.number = this.number + 1;\n}\n</code></pre></div>\n<p>Y nuestro <strong>onClick</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;button onClick={numberMobxClass.increase.bind(this)} >Increase Number&#x3C;/button>\n</code></pre></div>\n<p>Veamos que pasa cuando pulsamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.37.48.png\" alt=\"Log with this\"><br>\nNo nos da error pero si nos fijamos en lo que nos devuelve nuestro log, la propiedad <strong>number</strong> es <strong>NaN</strong> y eso ¿por qué? Pues porque realmente estamos pasando con <strong>bind</strong> el <strong>this</strong> de nuestro componente <strong>IncreaseNumber</strong> el cual no tiene esa propiedad, hagamos un pequeño ejemplo para verlo, creemos una propiedad en el componente <strong>IncreaseNumber</strong> como hemos visto en anteriores post y veamos el log ahora.<br>\nEl componente <strong>IncreaseNumber</strong> quedaria asi</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">class IncreaseNumber extends Component {\n    constructor(){\n        super();\n        this.test = 2;\n        \n    }\n    render(){\n        return(\n        &#x3C;button onClick={numberMobxClass.increase.bind(this)} >Increase Number&#x3C;/button>\n        )\n    }\n}\n</code></pre></div>\n<p>Y al pulsar tenemos este log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.47.11.png\" alt=\"Testing this context\"><br>\nSi os fijáis <strong>number</strong> sigue siendo <strong>NaN</strong> pero sin embargo tenemos nuestra propiedad <strong>test</strong> con el valor que hemos puesto, entonces quiere decir que estamos pasando el <strong>contexto</strong> del componente <strong>IncreaseNumber</strong>.... y entonces como lo hacemos??...Es más fácil de lo que parece, <strong>onClick</strong> espera una función no?, pues simplemente usemos una función que cada vez que se use esta \"llame\" a nuestro método <strong>increase</strong> (al estilo típico de la programación habitual)<br>\nCon esta teoría nuestro <strong>onClick</strong> quedaría así</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;button onClick={() => numberMobxClass.increase()} >Increase Number&#x3C;/button>\n</code></pre></div>\n<p>Veamos lo que tiene <strong>this</strong> ahora<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.52.52.png\" alt=\"Log with number increase\"><br>\nAnda!! Ahora nuestro <strong>number</strong> si aumenta pero..... en nuestra página no se ve.....y eso?? bueno la explicación es sencilla no estamos <strong>\"observando\"</strong> la propiedad para que responda los cambios y como hacemos eso?...Fácil, importamos <strong>observer</strong> de la libreria <strong>mobx-react</strong> y le indicamos que observe donde estamos renderizando, es decir en <strong>App.js</strong>, por lo que el componente quedaría asi</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\nimport { observer } from 'mobx-react';\n\nclass App extends Component {\n  render() {\n    return (\n      &#x3C;div className=\"App\">\n        &#x3C;div className=\"App-header\">\n          &#x3C;img src={logo} className=\"App-logo\" alt=\"logo\" />\n          &#x3C;h2>Welcome to React&#x3C;/h2>\n        &#x3C;/div>\n        &#x3C;p className=\"App-intro\">\n         We started working below this line\n        &#x3C;/p>\n        &#x3C;h2>{ numberMobxClass.number }&#x3C;/h2>\n        &#x3C;IncreaseNumber/>\n      &#x3C;/div>\n    );\n  }\n}\n\nexport default observer(App);\n</code></pre></div>\n<p>Y voilá ya tenemos nuestro numero aumentando en nuestra página<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-15.00.31.png\" alt=\"The meaning of life\"></p>\n<p>Espero que quede más o menos claro como estamos usando la característica <strong>observable</strong> que nos proporciona <strong>Mobx</strong>, que realmente nos facilita un poco estar pendiente de los estados o cambios de nuestras propiedades.</p>\n<p>En el siguiente post seguiremos viendo que más cosas podemos hacer con <strong>Mobx</strong>, nos vemos, 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 hablaremos de una librería muy útil llamada "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]},{"type":"text","value":" que entre otras cosas nos facilita un poco el desarrollo en cuanto a la comunicación entre componentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un componente a otro para realizar alguna modificación en alguna propiedad, pues bien "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]},{"type":"text","value":" nos facilita este planteamiento (entre otras cosas claro ;) ). Si queréis algo más de información aqui tenéis la página oficial de "},{"type":"element","tagName":"a","properties":{"href":"https://mobx.js.org/"},"children":[{"type":"text","value":"Mobx"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"instalacin"},"children":[{"type":"text","value":"Instalación"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para instalar "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"mobx"}]},{"type":"text","value":" usaremos nuestro magnífico "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":":"}]},{"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 mobx mobx-react --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos instalará en el proyecto los módulos de NodeJS necesarios para poder trabajar con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"usandomobx"},"children":[{"type":"text","value":"Usando Mobx"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien vamos a empezar a partir de la estructura de proyecto que teniamos en el post anterior (tras ejecutar nuestro create-app....)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a trabajar sobre el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.js"}]},{"type":"text","value":" que es el componente que se esta rendeando por defecto, pero vamos a cambiarlo un poco y asi vemos que realmente estamos en este punto, vamos a cambiar la frase que aparece debajo de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Welcome to React"}]},{"type":"text","value":" para indicar que trabajaremos despues de esa linea:"}]},{"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":"import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n      </div>\n    );\n  }\n}\n\nexport default App;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tras guardar, automáticamente tendriamos algo similar a"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-09-at-13.37.40.png","alt":"Started working"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBien ya sabemos donde estamos, ahora haremos un ejemplo simple para ver que es lo que conseguimos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]},{"type":"text","value":", vamos a mostrar un número y este aumentará cuando pulsemos un botón."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPrimero mostremos nuestro número, en un principio es algo sencillo que ya hemos visto no?, creamos un componente nuevo y lo indicamos en el componente que se esta renderizando como principal no??...... si esa es una opción pero al final estaríamos haciendo lo mismo que ya hemos visto y entonces para que queremos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"mobx"}]},{"type":"text","value":" no??. Pues bien la teoría del componente es válida a medias, vamos a crear una clase y en esta tenemos que importar "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"extendObservable"}]},{"type":"text","value":" de la librería de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"mobx"}]},{"type":"text","value":". Yo le he puesto el nombre "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"FirstMobxClass.js"}]},{"type":"text","value":" y esto es lo que ponemos"}]},{"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":"import {extendObservable} from 'mobx'\n\nclass FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        })\n    }\n}\n\n//Creamos una nueva instancia de nuestra clase,la almacenamos\n// y la exportamos para que se tenga acceso desde fuera\n//de esta clase\nvar numberMobxClass = new FirstMobxClass();\n\nexport default numberMobxClass;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con esto tendríamos una variable con una propiedad number que deberíamos poder usar. Para ello volvamos a nuestra clase App.js 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":"import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n        <h2>{ numberMobxClass.number }</h2>\n      </div>\n    );\n  }\n}\n\nexport default App;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para diferenciar los imports que ya teniamos de los nuevos he indicado el comentario "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"our imports"}]},{"type":"text","value":". Como véis lo que importamos es nuestra variable del fichero con nombre "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"FirstMobxClass"}]},{"type":"text","value":" y para usarlo nos valemos de las magias del lenguaje "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"JSX"}]},{"type":"text","value":" y con 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":"<h2>{ numberMobxClass.number }</h2>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tendríamos nuestra linea con el número que hemos puesto"},{"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-09-at-14.01.56.png","alt":"FirstMobx"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo siguiente será crear nuestro botón, en este caso seguimos la teoría inicial de los componentes que ya sabíamos, me refiero a que lo creamos como un componente normal. Creamos el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber.js"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"import React, { Component } from 'react';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        <button>Increase Number</button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"De momento nada nuevo, para verlo lo importamos en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.js"}]},{"type":"text","value":" y lo ponemos a continuación, es decir ahora en App.js debajo de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Our imports"}]},{"type":"text","value":" añadimos un import más debajo del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"numberMobxClass"}]}]},{"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":"//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y luego debajo de nuestro número le ponemos el botón"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<h2>{ numberMobxClass.number }</h2>\n<IncreaseNumber/>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y al guardar ya veríamos nuestro botón"},{"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-09-at-14.12.23.png","alt":"NewButton"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPero aunque pulsemos de momento no hace nada no??....continuemos ahora para añadirle funcionalidad. Al igual que haciamos antes necesitamos un método que haga que aumente nuestro número, y al igual que haciamos antes lo mejor es que lo creemos en el mismo punto que donde tenemos nuestra propiedad. Esto es tan simple como sumarle 1 al número, es decir añadimos a nuestra clase "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"FirstMobxClass"}]},{"type":"text","value":" el método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"increase"}]}]},{"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":"class FirstMobxClass {\n    constructor(){\n        //Recibe el objeto a observar y las propiedades\n        extendObservable(this,{\n            number: 1\n        });\n    }\n    increase(){\n        this.number = this.number + 1;\n    }\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos nuestro método ahora indiquemosle a nuestro botón que tiene que usarlo, probemos a ponerlo directamente con un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"onClick"}]},{"type":"text","value":" en el componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber"}]}]},{"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":"import React, { Component } from 'react';\nimport numberMobxClass from './FirstMobxClass';\n\nclass IncreaseNumber extends Component {\n    render(){\n        return(\n        <button onClick={numberMobxClass.increase} >Increase Number</button>\n        )\n    }\n}\n\nexport default IncreaseNumber;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis hemos importado nuestra clase "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"numberMobxClass"}]},{"type":"text","value":" y hemos usado nuestro método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"increase"}]},{"type":"text","value":" directamente en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"onClick"}]},{"type":"text","value":", bien si guardamos vemos que la página renderiza bien pero que pasa si pulsamos.......UPSSS!!!"},{"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-09-at-14.33.03.png","alt":"Error this==null"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos que nos sale este error, y eso es  como os podéis imaginar que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"this"}]},{"type":"text","value":" no tiene nada, diréis \"pues entonces podemos ponerle un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bind"}]},{"type":"text","value":" igual que haciamos antes y ya esta\", bueno pues vamos a probarlo a ver que pasa y de paso le ponemos al método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"increase"}]},{"type":"text","value":" un log para ver que tiene "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"this"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEl método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"increase"}]},{"type":"text","value":" ahora quedaria así"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"increase(){\n    console.log(this);\n    this.number = this.number + 1;\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"onClick"}]}]},{"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":"<button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos que pasa cuando pulsamos"},{"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-09-at-14.37.48.png","alt":"Log with this"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nNo nos da error pero si nos fijamos en lo que nos devuelve nuestro log, la propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"number"}]},{"type":"text","value":" es "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NaN"}]},{"type":"text","value":" y eso ¿por qué? Pues porque realmente estamos pasando con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bind"}]},{"type":"text","value":" el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"this"}]},{"type":"text","value":" de nuestro componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber"}]},{"type":"text","value":" el cual no tiene esa propiedad, hagamos un pequeño ejemplo para verlo, creemos una propiedad en el componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber"}]},{"type":"text","value":" como hemos visto en anteriores post y veamos el log ahora."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEl componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber"}]},{"type":"text","value":" quedaria asi"}]},{"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":"class IncreaseNumber extends Component {\n    constructor(){\n        super();\n        this.test = 2;\n        \n    }\n    render(){\n        return(\n        <button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>\n        )\n    }\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y al pulsar tenemos este log"},{"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-09-at-14.47.11.png","alt":"Testing this context"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi os fijáis "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"number"}]},{"type":"text","value":" sigue siendo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NaN"}]},{"type":"text","value":" pero sin embargo tenemos nuestra propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"test"}]},{"type":"text","value":" con el valor que hemos puesto, entonces quiere decir que estamos pasando el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"contexto"}]},{"type":"text","value":" del componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"IncreaseNumber"}]},{"type":"text","value":".... y entonces como lo hacemos??...Es más fácil de lo que parece, "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"onClick"}]},{"type":"text","value":" espera una función no?, pues simplemente usemos una función que cada vez que se use esta \"llame\" a nuestro método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"increase"}]},{"type":"text","value":" (al estilo típico de la programación habitual)"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nCon esta teoría nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"onClick"}]},{"type":"text","value":" quedaría así"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<button onClick={() => numberMobxClass.increase()} >Increase Number</button>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos lo que tiene "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"this"}]},{"type":"text","value":" ahora"},{"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-09-at-14.52.52.png","alt":"Log with number increase"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAnda!! Ahora nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"number"}]},{"type":"text","value":" si aumenta pero..... en nuestra página no se ve.....y eso?? bueno la explicación es sencilla no estamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"\"observando\""}]},{"type":"text","value":" la propiedad para que responda los cambios y como hacemos eso?...Fácil, importamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"observer"}]},{"type":"text","value":" de la libreria "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"mobx-react"}]},{"type":"text","value":" y le indicamos que observe donde estamos renderizando, es decir en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.js"}]},{"type":"text","value":", por lo que el componente quedaría asi"}]},{"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":"import React, { Component } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\n//Our imports\nimport numberMobxClass from './FirstMobxClass';\nimport IncreaseNumber from './IncreaseNumber';\nimport { observer } from 'mobx-react';\n\nclass App extends Component {\n  render() {\n    return (\n      <div className=\"App\">\n        <div className=\"App-header\">\n          <img src={logo} className=\"App-logo\" alt=\"logo\" />\n          <h2>Welcome to React</h2>\n        </div>\n        <p className=\"App-intro\">\n         We started working below this line\n        </p>\n        <h2>{ numberMobxClass.number }</h2>\n        <IncreaseNumber/>\n      </div>\n    );\n  }\n}\n\nexport default observer(App);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y voilá ya tenemos nuestro numero aumentando en nuestra página"},{"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-09-at-15.00.31.png","alt":"The meaning of life"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Espero que quede más o menos claro como estamos usando la característica "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"observable"}]},{"type":"text","value":" que nos proporciona "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]},{"type":"text","value":", que realmente nos facilita un poco estar pendiente de los estados o cambios de nuestras propiedades."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En el siguiente post seguiremos viendo que más cosas podemos hacer con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Mobx"}]},{"type":"text","value":", nos vemos, un abrazooorrrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"instalacin","heading":"Instalación"},{"id":"usandomobx","heading":"Usando Mobx"}]},"featureImageSharp":{"base":"Captain-Atom-1.jpg","publicURL":"/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom-1.jpg","imageMeta":{"width":864,"height":648},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQCBv/EABYBAQEBAAAAAAAAAAAAAAAAAAMBAv/aAAwDAQACEAMQAAABojay1bnBz//EABkQAQACAwAAAAAAAAAAAAAAAAECAwARE//aAAgBAQABBQKoAmdchqqPFMlZGuC7f//EABcRAQEBAQAAAAAAAAAAAAAAAAEAEiH/2gAIAQMBAT8BONov/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERE0H/2gAIAQIBAT8BbK50/8QAHhAAAwAABwEAAAAAAAAAAAAAAAERAhIiMTJRUmH/2gAIAQEABj8C0x9lWxlq+j9ImHkVn//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHlOmjsuNqMAiJQe2TspkuwMcZ4otX5GdLXWf/aAAwDAQACAAMAAAAQy/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQBB/9oACAEDAQE/ECLJZf/EABYRAQEBAAAAAAAAAAAAAAAAAAERAP/aAAgBAgEBPxBJcpVz/8QAHBABAAIDAAMAAAAAAAAAAAAAAQARITFBUWHR/9oACAEBAAE/ECGZHOFc9RXVMNQfYPyzYFbcsWTgugFwsFDeqNnrnxyXBPYm2f/Z","aspectRatio":1.3358778625954197,"src":"/static/ea41313c22f611d45d277d453c4273d1/ea4ab/Captain-Atom-1.jpg","srcSet":"/static/ea41313c22f611d45d277d453c4273d1/477ba/Captain-Atom-1.jpg 175w,\n/static/ea41313c22f611d45d277d453c4273d1/06776/Captain-Atom-1.jpg 350w,\n/static/ea41313c22f611d45d277d453c4273d1/ea4ab/Captain-Atom-1.jpg 700w,\n/static/ea41313c22f611d45d277d453c4273d1/fc1a6/Captain-Atom-1.jpg 864w","srcWebp":"/static/ea41313c22f611d45d277d453c4273d1/89afa/Captain-Atom-1.webp","srcSetWebp":"/static/ea41313c22f611d45d277d453c4273d1/9fca7/Captain-Atom-1.webp 175w,\n/static/ea41313c22f611d45d277d453c4273d1/37a4e/Captain-Atom-1.webp 350w,\n/static/ea41313c22f611d45d277d453c4273d1/89afa/Captain-Atom-1.webp 700w,\n/static/ea41313c22f611d45d277d453c4273d1/65e54/Captain-Atom-1.webp 864w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"allGhostPost":{"edges":[{"node":{"id":"Ghost__Post__5a338158333e0f134c248f3e","title":"Don't stop the party: Node JS(XIII) Cluster","slug":"dont-stop-the-party-node-js-xiii-cluster","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/nodebaner-1.jpg","excerpt":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que\nveremos con será, después de MongoDB, como usar las 2 cosas para hacer una API\ncompleta.\nAunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo\nque veremos a continuación podemos aumentar el rendimiento de nuestra aplicación\nnotablemente (eso sí, siempre dependiendo del entorno).\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más\nservicios, programas, ordenadores, se","custom_excerpt":null,"visibility":"public","created_at_pretty":"11 Oct 2017","published_at_pretty":"16 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-10-11T08:33:26.000+02:00","published_at":"2017-10-16T10:28:00.000+02:00","updated_at":"2018-01-22T09:34:26.000+01:00","meta_title":"Don't stop the party: Node JS(XIII) Cluster","meta_description":"Veremos como podemos configurar un Cluster de servicios de NodeJS para aumentar nuestro rendimiento casi exponencialmente.","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que\nveremos con será, después de MongoDB, como usar las 2 cosas para hacer una API\ncompleta.\nAunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo\nque veremos a continuación podemos aumentar el rendimiento de nuestra aplicación\nnotablemente (eso sí, siempre dependiendo del entorno).\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más\nservicios, programas, ordenadores, servidores....que funcionan como uno solo.\nBajo este concepto tendríamos varías opciones de configuración: balanceo de\ncarga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la \nWiki [https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)]\nEn nuestro caso, NodeJS, nos permite tener varios workers que trabajan por si\nsolos, para hacerlo simple es como si iniciaramos varias veces nuestra\naplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un\nproceso master que gestiona el resto y podemos pasar datos, comunicar eventos o\nlo que necesitemos entre los workers, entre los workers y el master y\nviceversa).\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que\ninicie el server para escuchar las peticiones por lo que vamosa nuestro proyecto\nde Express y dentro de la carpeta bin en el fichero www hacemos lo siguiente:\nBuscamos la linea donde tenemos el comentario Create server\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n\nY justo encima ponemos lo siguiente:\n\nconst cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n\n\nComo véis lo que hacemos es requerir el módulo cluster y básicamente es que si\nes el Master comprobamos cuantas CPUs tenemos y generamos un worker por cada\nuna. El numCpus lo que devuelve es un array donde cada elemento es información\nde cada CPU, yo simplemente he recorrido el array con el map y por cada elemento\nle he indicado que genere un worker. Esto se podría hacer de más formas con un \nfor normal o como queráis.\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha\niniciado un worker, justo debajo de los server.on y cerramos el else\n\nserver.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n\n\nBien creo que ya estamos listos para ejecutarlo, asi que ya sabéis\n\nnpm start\n\n\nY si miramos el log\n\nA mi me ha arrancado 4 workers, esto dependerá del número de CPUs de cada\nequipo.\nHablemos un poco más de como funciona un cluster en Node. En este caso\nespecífico se útiliza el método round-robin\n[https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin] para repartir la\ncarga entre los workers (lo mejor es que miréis el link que he puesto si queréis\nsaber como funciona).\n\nTango el master como los workers producen eventos a los que nos podemos \nsuscribir, al mismo estilo que hicimos con el event emitter\n[https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/] en su momento,\nlo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es\nque miréis la documentación oficial\n[https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html] que como veréis\nviene con mucho código de ejemplo para que lo entendáis mejor.\nTambién es posible que el master mande mensajes a los workers, veamoslo con un\npequeño ejemplo. Dentro del if, es decir en el master añadimos\n\n //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n\n\nY en el else donde instanciamos los workers\n\nprocess.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n\n\nNos suscribimos al evento message y devolvemos un mensaje en consola con el\nmensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje\nque hemos pasado a cada worker, y además cada vez que ejecutemos nos aparecerá\nen distinto momento ya que no sabemos cuando se instancia cada worker\n\n\n\nEsto solo es un ejemplo si repasais la documentación veréis que podéis hacer\nmultitud de cosas distintas ;)\n\nBueno y hasta aquí la parte de Cluster, como habéis visto es relativamente\nsencillo y ya podéis usarlo tranquilamente en vuestros proyectos con NodeJS.\n\nTambién (por el momento) aquí finalizamos la parte específica de Node ya lo\nsiguiente que veremos será usandolo con MongoDB para trabajar con esta base de\ndatos y crear una API Rest con un entorno más realista, así que empezaré con una\nnueva línea dedicada a MongoDB dentro de nada, espero que la parte de Node os\nhaya parecido interesante y suficiente para poder realizar vuestros propios\nproyectos.\n\nEstad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr","html":"<!--kg-card-begin: markdown--><p>Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa.<br>\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno).<br>\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la <a href=\"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)\">Wiki</a><br>\nEn nuestro caso, NodeJS, nos permite tener varios <em>workers</em> que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso <em>master</em> que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa).<br>\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el <em>server</em> para <em>escuchar</em> las peticiones por lo que vamosa nuestro proyecto de <em>Express</em> y dentro de la carpeta <strong>bin</strong> en el fichero <strong>www</strong> hacemos lo siguiente:<br>\nBuscamos la linea donde tenemos el comentario <em>Create server</em></p>\n<pre><code>/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre>\n<p>Y justo encima ponemos lo siguiente:</p>\n<pre><code>const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() =&gt; {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre>\n<p>Como véis lo que hacemos es <em>requerir</em> el módulo <strong>cluster</strong> y básicamente es que si es el <em>Master</em> comprobamos cuantas CPUs tenemos y generamos un <em>worker</em> por cada una. El <em>numCpus</em> lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un <em>worker</em>. Esto se podría hacer de más formas con un <em>for</em> normal o como queráis.<br>\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los <em>server.on</em> y cerramos el <em>else</em></p>\n<pre><code>server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n</code></pre>\n<p>Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis</p>\n<pre><code>npm start\n</code></pre>\n<p>Y si miramos el log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png\" alt=\"Workers Started\"><br>\nA mi me ha arrancado 4 <em>workers</em>, esto dependerá del número de CPUs de cada equipo.<br>\nHablemos un poco más de como funciona un cluster en <em>Node</em>. En este caso específico se útiliza el método <a href=\"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin\"><strong>round-robin</strong></a> para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona).</p>\n<p>Tango el <em>master</em> como los <em>workers</em> producen eventos a los que nos podemos <em>suscribir</em>, al mismo estilo que hicimos con el <a href=\"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/\"><em>event emitter</em></a> en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la <a href=\"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html\">documentación oficial</a> que como veréis viene con mucho código de ejemplo para que lo entendáis mejor.<br>\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del <strong>if</strong>, es decir en el <em>master</em> añadimos</p>\n<pre><code> //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(&quot;Hi ninjaWorker 2&quot;)\n    workersOnline[4].send(&quot;Hi ninjaWorker 4&quot;)\n</code></pre>\n<p>Y en el <em>else</em> donde instanciamos los <em>workers</em></p>\n<pre><code>process.on('message',(message)=&gt;{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n</code></pre>\n<p>Nos suscribimos al evento <em>message</em> y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada <em>worker</em>, y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada <em>worker</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png\" alt=\"Master send event 1\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png\" alt=\"Master send event 2\"></p>\n<p>Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)</p>\n<p>Bueno y hasta aquí la parte de <em>Cluster</em>, como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con <em>NodeJS</em>.</p>\n<p>También (por el momento) aquí finalizamos la parte específica de <strong>Node</strong> ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una <em>API Rest</em> con un entorno más realista, así que empezaré con una nueva línea dedicada a <em>MongoDB</em> dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos.</p>\n<p>Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xiii-cluster/","canonical_url":null,"uuid":"f63943af-060c-435b-8f97-b2c6f09734da","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59ddbb3658177700014ca3b2","reading_time":4,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa.<br>\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno).<br>\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la <a href=\"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)\">Wiki</a><br>\nEn nuestro caso, NodeJS, nos permite tener varios <em>workers</em> que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso <em>master</em> que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa).<br>\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el <em>server</em> para <em>escuchar</em> las peticiones por lo que vamosa nuestro proyecto de <em>Express</em> y dentro de la carpeta <strong>bin</strong> en el fichero <strong>www</strong> hacemos lo siguiente:<br>\nBuscamos la linea donde tenemos el comentario <em>Create server</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre></div>\n<p>Y justo encima ponemos lo siguiente:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n</code></pre></div>\n<p>Como véis lo que hacemos es <em>requerir</em> el módulo <strong>cluster</strong> y básicamente es que si es el <em>Master</em> comprobamos cuantas CPUs tenemos y generamos un <em>worker</em> por cada una. El <em>numCpus</em> lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un <em>worker</em>. Esto se podría hacer de más formas con un <em>for</em> normal o como queráis.<br>\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los <em>server.on</em> y cerramos el <em>else</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n</code></pre></div>\n<p>Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm start\n</code></pre></div>\n<p>Y si miramos el log<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png\" alt=\"Workers Started\"><br>\nA mi me ha arrancado 4 <em>workers</em>, esto dependerá del número de CPUs de cada equipo.<br>\nHablemos un poco más de como funciona un cluster en <em>Node</em>. En este caso específico se útiliza el método <a href=\"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin\"><strong>round-robin</strong></a> para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona).</p>\n<p>Tango el <em>master</em> como los <em>workers</em> producen eventos a los que nos podemos <em>suscribir</em>, al mismo estilo que hicimos con el <a href=\"/dont-stop-the-party-node-js-v/\"><em>event emitter</em></a> en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la <a href=\"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html\">documentación oficial</a> que como veréis viene con mucho código de ejemplo para que lo entendáis mejor.<br>\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del <strong>if</strong>, es decir en el <em>master</em> añadimos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"> //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n</code></pre></div>\n<p>Y en el <em>else</em> donde instanciamos los <em>workers</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">process.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n</code></pre></div>\n<p>Nos suscribimos al evento <em>message</em> y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada <em>worker</em>, y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada <em>worker</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png\" alt=\"Master send event 1\"><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png\" alt=\"Master send event 2\"></p>\n<p>Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)</p>\n<p>Bueno y hasta aquí la parte de <em>Cluster</em>, como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con <em>NodeJS</em>.</p>\n<p>También (por el momento) aquí finalizamos la parte específica de <strong>Node</strong> ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una <em>API Rest</em> con un entorno más realista, así que empezaré con una nueva línea dedicada a <em>MongoDB</em> dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos.</p>\n<p>Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAunque sea lo último no tiene porque dejar de ser interesante,  ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la "},{"type":"element","tagName":"a","properties":{"href":"https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)"},"children":[{"type":"text","value":"Wiki"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEn nuestro caso, NodeJS, nos permite tener varios "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":" que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPara configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"server"}]},{"type":"text","value":" para "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"escuchar"}]},{"type":"text","value":" las peticiones por lo que vamosa nuestro proyecto de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Express"}]},{"type":"text","value":" y dentro de la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"bin"}]},{"type":"text","value":" en el fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"www"}]},{"type":"text","value":" hacemos lo siguiente:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBuscamos la linea donde tenemos el comentario "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Create server"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y justo encima ponemos lo siguiente:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const cluster = require('cluster')\n\nif (cluster.isMaster){\n    \n    console.log(`Master is running in process ${process.pid}`)\n    const numCPUS = require('os').cpus()\n    numCPUS.map(() => {\n      cluster.fork()\n    }) \n      \n  \n}else {\n\n/**\n * Create HTTP server.\n */\n\nvar server = http.createServer(app);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis lo que hacemos es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerir"}]},{"type":"text","value":" el módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"cluster"}]},{"type":"text","value":" y básicamente es que si es el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Master"}]},{"type":"text","value":" comprobamos cuantas CPUs tenemos y generamos un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":" por cada una. El "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"numCpus"}]},{"type":"text","value":" lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":". Esto se podría hacer de más formas con un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"for"}]},{"type":"text","value":" normal o como queráis."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPara ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"server.on"}]},{"type":"text","value":" y cerramos el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"else"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"server.listen(port);\nserver.on('error', onError);\nserver.on('listening', onListening);\nconsole.log(`Worker ${process.pid} Started`)\n} //No nos olvidemos de cerrar el else en este punto\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm start\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y si miramos el log"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png","alt":"Workers Started"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nA mi me ha arrancado 4 "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":", esto dependerá del número de CPUs de cada equipo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nHablemos un poco más de como funciona un cluster en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":". En este caso específico se útiliza el método "},{"type":"element","tagName":"a","properties":{"href":"https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"round-robin"}]}]},{"type":"text","value":" para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tango el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" como los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]},{"type":"text","value":" producen eventos a los que nos podemos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"suscribir"}]},{"type":"text","value":", al mismo estilo que hicimos con el "},{"type":"element","tagName":"a","properties":{"href":"/dont-stop-the-party-node-js-v/"},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"event emitter"}]}]},{"type":"text","value":" en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la "},{"type":"element","tagName":"a","properties":{"href":"https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html"},"children":[{"type":"text","value":"documentación oficial"}]},{"type":"text","value":" que como veréis viene con mucho código de ejemplo para que lo entendáis mejor."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTambién es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"if"}]},{"type":"text","value":", es decir en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"master"}]},{"type":"text","value":" añadimos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":" //Nos da una lista con los workers que tenemos\n    const workersOnline = cluster.workers\n\n    workersOnline[2].send(\"Hi ninjaWorker 2\")\n    workersOnline[4].send(\"Hi ninjaWorker 4\")\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"else"}]},{"type":"text","value":" donde instanciamos los "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"workers"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"process.on('message',(message)=>{\n  console.log(`Soy un worker y este es el mensaje ${message}`)\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos suscribimos al evento "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"message"}]},{"type":"text","value":" y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"text","value":", y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"worker"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png","alt":"Master send event 1"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png","alt":"Master send event 2"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bueno y hasta aquí la parte de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Cluster"}]},{"type":"text","value":", como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"También (por el momento) aquí finalizamos la parte específica de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":" ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"API Rest"}]},{"type":"text","value":" con un entorno más realista, así que empezaré con una nueva línea dedicada a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"MongoDB"}]},{"type":"text","value":" dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[]},"featureImageSharp":{"base":"nodebaner-1.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-1.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-1.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-1.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-1.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-1.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-1.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-1.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-1.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-1.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-1.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-1.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-1.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-1.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-1.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__5a338158333e0f134c248f38","title":"Don't stop the party: Node JS(XII) Promesas","slug":"dont-stop-the-party-node-js-xii-promesas","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/nodebaner.jpg","excerpt":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero\nrealmente son muy útiles.\n\nPromesas\nLas promesas, si no estoy mal, se añadieron oficialmente en JS a partir de\nES6...y por resumir un poco, son como callbacks de finalización pero en bonito,\nexplicome....cuando necesitamos encadenar métodos que continenen callbacks\npodemos terminar con un código de este estilo\n\n\nRealmente es raro que nuestro código termine así, pero realmente esa es la\ntendencia , ¿verdad?.. bueno p","custom_excerpt":null,"visibility":"public","created_at_pretty":"3 Oct 2017","published_at_pretty":"12 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-10-03T21:00:17.000+02:00","published_at":"2017-10-12T10:10:00.000+02:00","updated_at":"2018-01-22T09:34:34.000+01:00","meta_title":"Don't stop the party: Node JS(XII) Promesas","meta_description":"Hablaremos de las Promesas que son parte de todo el stack de JavaScript y que nos serán muy útiles en nuestros desarrollos con NodeJS","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero\nrealmente son muy útiles.\n\nPromesas\nLas promesas, si no estoy mal, se añadieron oficialmente en JS a partir de\nES6...y por resumir un poco, son como callbacks de finalización pero en bonito,\nexplicome....cuando necesitamos encadenar métodos que continenen callbacks\npodemos terminar con un código de este estilo\n\n\nRealmente es raro que nuestro código termine así, pero realmente esa es la\ntendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las \npromesas es esa. Por definir concretamente:\nUna promesa es un objeto que, si todavía no ha terminado, aseguramos que se\ncompletará más adelante.\n\nSupongo que con esa frase queda más claro todavía qué es una promesa (y también\nsu nombre jeje). Las promesas tienen tres estados en su ciclo de vida:\n\n * Pendiente(pending): Como su nombre indica todavía está sin cumplir y cambiará\n   de estado en algún momento.\n * Completada correctamente(Fullfilled/resolve): Es decir, ha hecho su trabajo\n   correctamente y ha devuelto un valor.\n * Rechazada(rejected): En su proceso de ejecución ha dado algún tipo de error y\n   ha sido completada con error devolviendonos la razón.\n\nVeamos ahora como podemos crear una promesa\n\nvar prom = new Promise(function(resolve,reject){\n})\n\n\nBásicamente creamos un nuevo objeto Promise el cual tiene una función que recibe\ndos parámetros, con un nombre bastante intuitivo por cierto:\n\n * resolve: Llamaremos a resolve cuando todo haya ido bien y le pasamos el\n   resultado que recibirá la siguiente promesa o función.\n * reject: Llamaremos a reject cuando tengamos un error, al cual le pasaremos el\n   error.\n\nY, ¿como usamos esto? Bastante sencillo\n\nprom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n\n\nEsto lo que hace es ejecutar la promesa que hemos creado y a continuación (then)\nse ejecutará la función dentro del then donde resultado es el parámetro que\nhemos recibido desde la promesa con resolve. En el caso de que algo hubiera\nfallado o el resultado fuera insatisfactorio ejecutariamos reject con el error o\nla información que quisieramos, la cual capturaría el primer catch que\nencontrará la cadena de promesas. Por si no os lo habéis imaginado nosotros\npodemos poner todas las promesas y catch que queramos\n\nprom.then().then().then().catch().then().catch()\n\n\nY en el orden que las hemos escritor se irian ejecutando, y también según ese\norden el primer catch que se encontrara sería el que respondería en caso de\ntener un resultado reject.\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún catch. Vamos\na crear un método nuevo junto con el que ya teníamos que lo vamos a modificar,\nla idea es que cada promesa vaya encadenando un String hasta mostrarlo al final,\naunque en este caso lo que haremos será mostrarlo en cada paso para que se vea\nque esta haciendo.\nPrimero cambiamos nuestra función sleep\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n\n\nLe pasamos el parámetro hero y devolvemos un string. A continuación creamos otro\nmétodo que vaya encadenando\n\nfunction heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n\n\nDe momento dejamos comentada la parte de reject para ver el resultado. Como véis\nla función recibe un parámetro result (este primer parámetro sería lo que nos\ndevuelve la promesa en caso de resolve) y también un parámetro extra con el\nnombre de otro hero y luego simplemente lo juntamos todo para que lo devuelva en\n2 segundos.\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas\n\nprom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n\n\nDe paso le he metido un catch para probar el error más adelante. Fijáos que lo\nque hacemos es retornar dentro de una función anónima, que es la que recibe \nresult, la promesa resultante de nuestra función heros, si no necesitaramos \nresult no tendríamos porque meterlo dentro de otra función, bastaría solo con\nusar heros(\"New Hero\"). Bueno y ahora si lo probamos\n\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.\nPor último vamos a probar el catch para que veais como funciona, lo que haremos\nserá descomentar el código que tenía reject y ya podríamos probarlo.\n\nVemos que cuando le toca el turno a Green Latern pasa por el catch pero no se\ndetiene y continua......eso es porque tenemos que cambiar como funciona el catch \nya que solo hemos puesto un console.log para que se vea que pasa por allí, para\nhacer que se detenga podemos poner\n\ncatch((err) => {\n    throw err  \n})\n\n\nY ahora sí tendríamos un error al estilo promesas\n\n\nCon promesas tenemos también otras opciones, por ejemplo podemos pasar un array\nde promesas y cuando terminen todas pasa al then o al catch según si ha dado\nerror o no.\n\nPromise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n\n\nCon Promise.all, pasamos una array de promesas y esperamos a que terminen todas,\ntenemos también la opción de que pase al then cuando responda la primera\n\nPromise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n\n\nEste concepto es útil por ejemplo si tenemos varios servidores de base de datos,\nhacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno\ntermine ya tenemos un resultado, lo que nos permite responder lo más rápido\nposible ignorando si un servidor tiene más carga que otro.\n\nAhora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en\nun extra o forma de usarlas que, si no me equivoco, salió en ES7 y para esto es\nnecesario tener Node actualizado a la última versión o por lo menos en la 7.6\n(creo), con node -v podéis ver en que versión estáis y actualizar si lo\nnecesitáis.\n\nConcretamente vamos a hablar de async/await. Estos nuevos métodos nos ayudan un\npoco con la gestión de las promesas, y de los callbacks por supuesto. Lo que\nhacemos con await es esperar a que una función termine y parece ser que como \nbest practice(o que tiene que ser si o sí más bien) tenemos que hacer ese código\nasíncrono asi que nos han puesto async para facilitarnos esa tarea. Y como\nfunciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos\nteníamos antes.\nPartimos de esto\n\n'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n\n\nSe supone que tenemos que usar await para que el código se espere a que termine\nla promesa y meterlo todo dentro de async...pues vamos\n\nasync function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n\n\nComo véis simplemente hemos puesto await al principio de la ejecución de nuestra\npromesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos\nmetido todo dentro de una función que empieza con async. Ahora vamos a usarlo\ncomo si de una promesa normal se tratase\n\nasyncPromise().then((result) => console.log(result))\n\n\nBien ya tenemos todo, ahora vamos a ejecutarlo\n\n\nComo habréis podido comprobar nos ha aparecido el log indicando que empieza y a\nlos 2 segundos nos ha mostrado el resultado como si de una promesa normal se\ntratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks\nde finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con\nestas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el\nlímite lo ponéis vosotros de como usar esto.\n\nCreo que por el momento vamos a dejar las promesas (o lo relacionado con ellas)\naquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos\nvisto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que\nsolo me quedaría un mini-post más de extras de Node y nos pondríamos ya con\nMongoDB.\n\nNos veeeemosssss un abrazooorrrrr","html":"<!--kg-card-begin: markdown--><p>Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles.</p>\n<h3 id=\"promesas\">Promesas</h3>\n<p>Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif\" alt=\"callBack_hell\"></p>\n<p>Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las <em>promesas</em> es esa. Por definir concretamente:<br>\n<em>Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante</em>.</p>\n<p>Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las <em>promesas</em> tienen tres estados en su ciclo de vida:</p>\n<ul>\n<li><strong>Pendiente(pending)</strong>: Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento.</li>\n<li><strong>Completada correctamente(Fullfilled/resolve)</strong>: Es decir, ha hecho su trabajo correctamente y ha devuelto un valor.</li>\n<li><strong>Rechazada(rejected)</strong>: En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón.</li>\n</ul>\n<p>Veamos ahora como podemos crear una promesa</p>\n<pre><code>var prom = new Promise(function(resolve,reject){\n})\n</code></pre>\n<p>Básicamente creamos un nuevo objeto <strong>Promise</strong> el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:</p>\n<ul>\n<li><strong>resolve</strong>: Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente <em>promesa</em> o función.</li>\n<li><strong>reject</strong>: Llamaremos a <em>reject</em> cuando tengamos un error, al cual le pasaremos el error.</li>\n</ul>\n<p>Y, ¿como usamos esto? Bastante sencillo</p>\n<pre><code>prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n</code></pre>\n<p>Esto lo que hace es ejecutar la promesa que hemos creado y a continuación (<strong>then</strong>) se ejecutará la función dentro del <em>then</em> donde <strong>resultado</strong> es el parámetro que hemos recibido desde la promesa con <em>resolve</em>. En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos <em>reject</em> con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de <em>promesas</em>. Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos</p>\n<pre><code>prom.then().then().then().catch().then().catch()\n</code></pre>\n<p>Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado <em>reject</em>.<br>\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún <em>catch</em>. Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo.<br>\nPrimero cambiamos nuestra función <em>sleep</em></p>\n<pre><code>//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) =&gt; {\n        setTimeout(() =&gt; {\n            resolve(&quot;La liga de la justicia: &quot; + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, &quot;Superman&quot;);\n</code></pre>\n<p>Le pasamos el parámetro <em>hero</em> y devolvemos un string. A continuación creamos otro método que vaya encadenando</p>\n<pre><code>function heros(result, hero){\n    \n    return new Promise((resolve,reject) =&gt; {\n\n        /*if (hero === &quot;Green Latern&quot;){\n           reject(&quot;No aparece esta vez&quot;)\n        }*/\n\n        console.log(result)\n        setTimeout(()=&gt; {  \n             resolve(result + &quot; &quot; + hero)\n        },2000)\n     })\n}\n</code></pre>\n<p>De momento dejamos comentada la parte de <em>reject</em> para ver el resultado. Como véis la función recibe un parámetro <em>result</em> (este primer parámetro sería lo que nos devuelve la promesa en caso de <em>resolve</em>) y también un parámetro extra con el nombre de otro <em>hero</em> y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos.<br>\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas</p>\n<pre><code>prom\n.then((result) =&gt; {\n    return heros(result, &quot;Batman&quot;)\n})\n.then((result) =&gt; {\n    return heros(result, &quot;Green Latern&quot;) \n})\n.then((result) =&gt; {\n    return heros(result, &quot;Wonder Woman&quot;)\n})\n.catch((err) =&gt; {\n    console.log(err)\n})\n.then((result) =&gt; {\n    return heros(result, &quot;Aquaman&quot;)\n})\n.then((result)=&gt; { \n    console.log(result)\n})\n</code></pre>\n<p>De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe <em>result</em>, la promesa resultante de nuestra función <em>heros</em>, si no necesitaramos <em>result</em> no tendríamos porque meterlo dentro de otra función, bastaría solo con usar <em>heros(&quot;New Hero&quot;)</em>. Bueno y ahora si lo probamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png\" alt=\"Example Multiple promises\"><br>\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.<br>\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png\" alt=\"Example Catch without return\"><br>\nVemos que cuando le toca el turno a <em>Green Latern</em> pasa por el <em>catch</em> pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el <em>catch</em> ya que solo hemos puesto un <em>console.log</em> para que se vea que pasa por allí, para hacer que se detenga podemos poner</p>\n<pre><code>catch((err) =&gt; {\n    throw err  \n})\n</code></pre>\n<p>Y ahora sí tendríamos un error al <em>estilo promesas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png\" alt=\"Promises error\"></p>\n<p>Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al <em>then</em> o al <em>catch</em> según si ha dado error o no.</p>\n<pre><code>Promise.all(arrayPromises)\n    .then((result) =&gt;{console.log(result)})\n    .catch((error){})\n</code></pre>\n<p>Con <em>Promise.all</em>, pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al <em>then</em> cuando responda la primera</p>\n<pre><code>Promise.race([arrayPromises])\n    .then((result) =&gt; { console.log(&quot;La más rápida ha sido&quot; + result)})\n</code></pre>\n<p>Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro.</p>\n<p>Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y <strong>para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)</strong>, con <strong>node -v</strong> podéis ver en que versión estáis y actualizar si lo necesitáis.</p>\n<p>Concretamente vamos a hablar de <strong>async/await</strong>. Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con <strong>await</strong> es esperar a que una función termine y parece ser que como <em>best practice</em>(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto <strong>async</strong> para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes.<br>\nPartimos de esto</p>\n<pre><code>'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) =&gt; {\n        setTimeout(() =&gt; {\n            resolve(&quot;La liga de la justicia: &quot; + hero)\n            \n        }, ms);\n    });\n}\n</code></pre>\n<p>Se supone que tenemos que usar <em>await</em> para que el código se espere a que termine la promesa y meterlo todo dentro de <em>async</em>...pues vamos</p>\n<pre><code>async function asyncPromise(){\n    console.log(&quot;Empezamos a contar&quot;)\n    return await sleep(2000,&quot;Superman&quot;)\n}\n</code></pre>\n<p>Como véis simplemente hemos puesto <em>await</em> al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con <em>async</em>. Ahora vamos a usarlo como si de una promesa normal se tratase</p>\n<pre><code>asyncPromise().then((result) =&gt; console.log(result))\n</code></pre>\n<p>Bien ya tenemos todo, ahora vamos a ejecutarlo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png\" alt=\"Async Await example\"></p>\n<p>Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones &quot;nuevas&quot; de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto.</p>\n<p>Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB.</p>\n<p>Nos veeeemosssss un abrazooorrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xii-promesas/","canonical_url":null,"uuid":"df54bc2b-2b01-4415-a567-2b5d30f1f162","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59d3de4158177700014ca384","reading_time":6,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles.</p>\n<h3 id=\"promesas\">Promesas</h3>\n<p>Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif\" alt=\"callBack_hell\"></p>\n<p>Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las <em>promesas</em> es esa. Por definir concretamente:<br>\n<em>Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante</em>.</p>\n<p>Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las <em>promesas</em> tienen tres estados en su ciclo de vida:</p>\n<ul>\n<li><strong>Pendiente(pending)</strong>: Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento.</li>\n<li><strong>Completada correctamente(Fullfilled/resolve)</strong>: Es decir, ha hecho su trabajo correctamente y ha devuelto un valor.</li>\n<li><strong>Rechazada(rejected)</strong>: En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón.</li>\n</ul>\n<p>Veamos ahora como podemos crear una promesa</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var prom = new Promise(function(resolve,reject){\n})\n</code></pre></div>\n<p>Básicamente creamos un nuevo objeto <strong>Promise</strong> el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:</p>\n<ul>\n<li><strong>resolve</strong>: Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente <em>promesa</em> o función.</li>\n<li><strong>reject</strong>: Llamaremos a <em>reject</em> cuando tengamos un error, al cual le pasaremos el error.</li>\n</ul>\n<p>Y, ¿como usamos esto? Bastante sencillo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n</code></pre></div>\n<p>Esto lo que hace es ejecutar la promesa que hemos creado y a continuación (<strong>then</strong>) se ejecutará la función dentro del <em>then</em> donde <strong>resultado</strong> es el parámetro que hemos recibido desde la promesa con <em>resolve</em>. En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos <em>reject</em> con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de <em>promesas</em>. Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom.then().then().then().catch().then().catch()\n</code></pre></div>\n<p>Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado <em>reject</em>.<br>\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún <em>catch</em>. Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo.<br>\nPrimero cambiamos nuestra función <em>sleep</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n</code></pre></div>\n<p>Le pasamos el parámetro <em>hero</em> y devolvemos un string. A continuación creamos otro método que vaya encadenando</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n</code></pre></div>\n<p>De momento dejamos comentada la parte de <em>reject</em> para ver el resultado. Como véis la función recibe un parámetro <em>result</em> (este primer parámetro sería lo que nos devuelve la promesa en caso de <em>resolve</em>) y también un parámetro extra con el nombre de otro <em>hero</em> y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos.<br>\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">prom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n</code></pre></div>\n<p>De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe <em>result</em>, la promesa resultante de nuestra función <em>heros</em>, si no necesitaramos <em>result</em> no tendríamos porque meterlo dentro de otra función, bastaría solo con usar <em>heros(\"New Hero\")</em>. Bueno y ahora si lo probamos<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png\" alt=\"Example Multiple promises\"><br>\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe.<br>\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png\" alt=\"Example Catch without return\"><br>\nVemos que cuando le toca el turno a <em>Green Latern</em> pasa por el <em>catch</em> pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el <em>catch</em> ya que solo hemos puesto un <em>console.log</em> para que se vea que pasa por allí, para hacer que se detenga podemos poner</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">catch((err) => {\n    throw err  \n})\n</code></pre></div>\n<p>Y ahora sí tendríamos un error al <em>estilo promesas</em><br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png\" alt=\"Promises error\"></p>\n<p>Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al <em>then</em> o al <em>catch</em> según si ha dado error o no.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Promise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n</code></pre></div>\n<p>Con <em>Promise.all</em>, pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al <em>then</em> cuando responda la primera</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Promise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n</code></pre></div>\n<p>Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro.</p>\n<p>Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y <strong>para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)</strong>, con <strong>node -v</strong> podéis ver en que versión estáis y actualizar si lo necesitáis.</p>\n<p>Concretamente vamos a hablar de <strong>async/await</strong>. Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con <strong>await</strong> es esperar a que una función termine y parece ser que como <em>best practice</em>(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto <strong>async</strong> para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes.<br>\nPartimos de esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n</code></pre></div>\n<p>Se supone que tenemos que usar <em>await</em> para que el código se espere a que termine la promesa y meterlo todo dentro de <em>async</em>...pues vamos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">async function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n</code></pre></div>\n<p>Como véis simplemente hemos puesto <em>await</em> al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con <em>async</em>. Ahora vamos a usarlo como si de una promesa normal se tratase</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">asyncPromise().then((result) => console.log(result))\n</code></pre></div>\n<p>Bien ya tenemos todo, ahora vamos a ejecutarlo<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png\" alt=\"Async Await example\"></p>\n<p>Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto.</p>\n<p>Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB.</p>\n<p>Nos veeeemosssss un abrazooorrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"promesas"},"children":[{"type":"text","value":"Promesas"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar  métodos que continenen callbacks podemos terminar con un código de este estilo"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/callBack_hell.gif","alt":"callBack_hell"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":" es esa. Por definir concretamente:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":" tienen tres estados en su ciclo de vida:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Pendiente(pending)"}]},{"type":"text","value":": Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Completada correctamente(Fullfilled/resolve)"}]},{"type":"text","value":": Es decir, ha hecho su trabajo correctamente y ha devuelto un valor."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Rechazada(rejected)"}]},{"type":"text","value":": En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos ahora como podemos crear una promesa"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var prom = new Promise(function(resolve,reject){\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Básicamente creamos un nuevo objeto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Promise"}]},{"type":"text","value":" el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":": Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesa"}]},{"type":"text","value":" o función."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":": Llamaremos a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" cuando tengamos un error, al cual le pasaremos el error."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y, ¿como usamos esto? Bastante sencillo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom.then(function(resultado){\n    //Lo que queramos hacer con el resultado\n}).catch(function(error){\n  //Lo que queramos hacer si hemos recibido error\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto lo que hace es ejecutar la promesa que hemos creado y a continuación ("},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":") se ejecutará la función dentro del "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" donde "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"resultado"}]},{"type":"text","value":" es el parámetro que hemos recibido desde la promesa con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":". En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"promesas"}]},{"type":"text","value":". Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom.then().then().then().catch().then().catch()\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nHagamos un ejemplo encadenando promesas y de paso le ponemos algún "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":". Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPrimero cambiamos nuestra función "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"sleep"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n    return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n        }, ms);\n    });\n}\n\nconst prom = sleep(2000, \"Superman\");\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le pasamos el parámetro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" y devolvemos un string. A continuación creamos otro método que vaya encadenando"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"function heros(result, hero){\n    \n    return new Promise((resolve,reject) => {\n\n        /*if (hero === \"Green Latern\"){\n           reject(\"No aparece esta vez\")\n        }*/\n\n        console.log(result)\n        setTimeout(()=> {  \n             resolve(result + \" \" + hero)\n        },2000)\n     })\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"De momento dejamos comentada la parte de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"reject"}]},{"type":"text","value":" para ver el resultado. Como véis la función recibe un parámetro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":" (este primer parámetro sería lo que nos devuelve la promesa en caso de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"resolve"}]},{"type":"text","value":") y también un parámetro extra con el nombre de otro "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"hero"}]},{"type":"text","value":" y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nYa tenemos nuestros métodos ahora vamos a encadenar las promesas"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"prom\n.then((result) => {\n    return heros(result, \"Batman\")\n})\n.then((result) => {\n    return heros(result, \"Green Latern\") \n})\n.then((result) => {\n    return heros(result, \"Wonder Woman\")\n})\n.catch((err) => {\n    console.log(err)\n})\n.then((result) => {\n    return heros(result, \"Aquaman\")\n})\n.then((result)=> { \n    console.log(result)\n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":", la promesa resultante de nuestra función "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros"}]},{"type":"text","value":", si no necesitaramos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"result"}]},{"type":"text","value":" no tendríamos porque meterlo dentro de otra función, bastaría solo con usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros(\"New Hero\")"}]},{"type":"text","value":". Bueno y ahora si lo probamos"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png","alt":"Example Multiple promises"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos como cada 2 segundos nos aparece el string con el nuevo héroe."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png","alt":"Example Catch without return"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVemos que cuando le toca el turno a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Green Latern"}]},{"type":"text","value":" pasa por el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" ya que solo hemos puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"console.log"}]},{"type":"text","value":" para que se vea que pasa por allí, para hacer que se detenga podemos poner"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"catch((err) => {\n    throw err  \n})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y ahora sí tendríamos un error al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"estilo promesas"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png","alt":"Promises error"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" o al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"catch"}]},{"type":"text","value":" según si ha dado error o no."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"Promise.all(arrayPromises)\n    .then((result) =>{console.log(result)})\n    .catch((error){})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Promise.all"}]},{"type":"text","value":", pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"then"}]},{"type":"text","value":" cuando responda la primera"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"Promise.race([arrayPromises])\n    .then((result) => { console.log(\"La más rápida ha sido\" + result)})\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)"}]},{"type":"text","value":", con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node -v"}]},{"type":"text","value":" podéis ver en que versión estáis y actualizar si lo necesitáis."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Concretamente vamos a hablar de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"async/await"}]},{"type":"text","value":". Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" es esperar a que una función termine y parece ser que como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"best practice"}]},{"type":"text","value":"(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":" para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPartimos de esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\n//Seria una funcion que devuelve una promesa\nfunction sleep(ms,hero) {\n   return new Promise((resolve,reject) => {\n        setTimeout(() => {\n            resolve(\"La liga de la justicia: \" + hero)\n            \n        }, ms);\n    });\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Se supone que tenemos que usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" para que el código se espere a que termine la promesa y meterlo todo dentro de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":"...pues vamos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"async function asyncPromise(){\n    console.log(\"Empezamos a contar\")\n    return await sleep(2000,\"Superman\")\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis simplemente hemos puesto "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"await"}]},{"type":"text","value":" al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"async"}]},{"type":"text","value":". Ahora vamos a usarlo como si de una promesa normal se tratase"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"asyncPromise().then((result) => console.log(result))\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien ya tenemos todo, ahora vamos a ejecutarlo"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png","alt":"Async Await example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones \"nuevas\" de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos veeeemosssss un abrazooorrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"promesas","heading":"Promesas"}]},"featureImageSharp":{"base":"nodebaner.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__5a338158333e0f134c248f37","title":"Don't stop the party: Node JS(XI) Autenticación","slug":"dont-stop-the-party-node-js-x-templates-o-vistas-2","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner-6.jpg","excerpt":"En este post vamos a centrarnos en algunas de las posibilidades de\nimplementación de autenticación en Node, concretamente hablaremos de lo que se\nconoce como Basic Auth y de JSON Web Token.\n\nBasic Auth\nEste sistema de autenticación es el más sencillo de todos, y a su vez no de lo\nmás seguro, pero puede que para un sistema sencillo o alguna aplicación interna\npueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero\nsi entras....pues bienvenido pásalo bien ;) ).\nVamos a con","custom_excerpt":null,"visibility":"public","created_at_pretty":"29 Sep 2017","published_at_pretty":"10 Oct 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-29T11:22:23.000+02:00","published_at":"2017-10-10T10:00:00.000+02:00","updated_at":"2018-01-22T09:36:28.000+01:00","meta_title":null,"meta_description":"Hablaremos de algunas de las posibilidades de autenticación en Node, concretamente hablaremos de lo que se conoce como Basic Auth y de JSON Web Token. ","og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"jlgarcia","url":"https://jlgarcia.fulldev.ninja/author/jlgarcia/","name":"Juan Luis Garcia Aparicio","bio":null,"cover_image":null,"profile_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/12/Perfil.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"Perfil.jpg","publicURL":"/static/b0de6281fb28a266510b3b09b9243e5a/Perfil.jpg","imageMeta":{"width":307,"height":307},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGzw6zC6zHn+cLYP//EAB0QAAICAQUAAAAAAAAAAAAAAAEDAAIEEyEiIzL/2gAIAQEAAQUCifca8KgcKWVfUpkHsG5pxX//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAgEFAAAAAAAAAAAAAAAAARARcQISIUFR/9oACAEBAAY/AhU88xkb7N06a8P/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8hR2pq40aqb+xIAeXibhW9JXr8joF4TBcSNe0//9oADAMBAAIAAwAAABDzDwD/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhUTFhcfD/2gAIAQEAAT8QyItrELaTlatLwU63MvEW6vUNdy4LZQDn7iVApV9VLtANdWwKkuYq4Er1VZ//2Q==","aspectRatio":1,"src":"/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg","srcSet":"/static/b0de6281fb28a266510b3b09b9243e5a/f340b/Perfil.jpg 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/22d64/Perfil.jpg 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/31709/Perfil.jpg 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/aa249/Perfil.jpg 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/0dc33/Perfil.jpg 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/60667/Perfil.jpg 307w","srcWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp","srcSetWebp":"/static/b0de6281fb28a266510b3b09b9243e5a/59cda/Perfil.webp 28w,\n/static/b0de6281fb28a266510b3b09b9243e5a/7da75/Perfil.webp 55w,\n/static/b0de6281fb28a266510b3b09b9243e5a/8678c/Perfil.webp 110w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f282e/Perfil.webp 165w,\n/static/b0de6281fb28a266510b3b09b9243e5a/a7b21/Perfil.webp 220w,\n/static/b0de6281fb28a266510b3b09b9243e5a/f59af/Perfil.webp 307w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null},"tags":[{"slug":"nodejs","url":"https://jlgarcia.fulldev.ninja/tag/nodejs/","name":"nodejs","visibility":"public","feature_image":null,"description":null,"meta_title":"NodeJS Ninjas","meta_description":"Aprenderemos desde lo básico este framework de JS para backend, muy bueno en concurrencia y en API Rest y que forma parte del stack MEAN o MERN.","featureImageSharp":null}],"plaintext":"En este post vamos a centrarnos en algunas de las posibilidades de\nimplementación de autenticación en Node, concretamente hablaremos de lo que se\nconoce como Basic Auth y de JSON Web Token.\n\nBasic Auth\nEste sistema de autenticación es el más sencillo de todos, y a su vez no de lo\nmás seguro, pero puede que para un sistema sencillo o alguna aplicación interna\npueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero\nsi entras....pues bienvenido pásalo bien ;) ).\nVamos a configurar por ejemplo nuestra ruta con heros, la que está en el fichero \nninjas.js para que nos solicite un usuario y contraseña.\n\nLo primero de todo como es habitual en Node, usaremos npm para instalar el\nmódulo necesario\n\nnpm install basic-auth --save\n\n\nA continuación lo que hacemos es requerir el módulo como siempre y lo siguiente\nen el middleware que queramos usamos lo que hemos requerido y le pasamos la\nrequest. Esto lo que hará será buscar datos de usuario y contraseña en ella.\n\n//Con esto importamos el módulo\nconst auth = require('basic-auth');\n\n\nY en nuestro middleware\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n\n\nAhora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas\nmás.\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos\nque responder a nuestro cliente desde nuestro middleware con un valor espécifico\nen la cabecera y ya de paso para hacerlo bien le ponemos el código de estado\npertinente (401 en este caso). Pero claro esto no es tan automático como podemos\npensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en\nnuestra constante userLogin, con todo esto de momento nuestro código sería el\nsiguiente\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\n\nSi ahora lo probamos tendríamos esto\n\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que\npongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de\nalguna forma. En un principio esto lo ideal sería tener una base de datos, un\nfichero o similar para comprobar tanto usuario como contraseña, en nuestro caso\nno tenemos implementado nada de esto por lo que de momento lo que haremos será\ncomprobarlo directamente en el código, pero tener en cuenta que en este punto lo\nque haríamos sería comprobar en algún lado que los datos son correctos\n\nrouter.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\n\nAhora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña\n\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más\nelegante, no creo que sea lo mejor hacer este código en todos los middleware que\nnecesitemos (bueno si es general para toda la aplicación solo necesitamos\nponerlo en el app.js y crear un middleware que responda a todas las request,\npero ese no creo que sea el escenario en general).\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una\ncarpeta lib que sera la que tendrá las librerías/módulos que creemos o\nimportemos y no lo hagamos con npm. Creamos un fichero auth.js y lo que haremos\nserá exportar el callback al que respondería un middleware\n\n'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n\n\nBásicamente he puesto el mismo código que habíamos añadido antes, solo que al\nfinal le hemos puesto un next() para que continue con el siguiente middleware\nque coincida.\nAhora vamos a módificar nuestra ruta ninjas para que use esto\n\n'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n\n\nHemos importado nuestro módulo y simplemente se lo hemos pasado como primer\nhandler del middleware. A un middleware le podemos pasar todos los handlers que\nqueramos y se irán ejecutando uno detrás de otro según vayan terminando.\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la\ncontraseña porque seguramente el navegador haya almacenado los datos que habéis\nintroducido anteriormente.\nBueno en cuanto a este método de autenticación poco más merece que miremos, es\nbastante sencillo y pueden existir otro tipo de implementaciones pero este sería\nel funcionamiento típico.\n\nJSON Web Token\nY, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero\nalmacenandola en el cliente, lo que aligera un poco la gestión de esto por parte\ndel backend y como su nombre indica lo hacemos en formato JSON.\nEl proceso sería el siguiente. El usuario se autentica con su usuario y\ncontraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el\nbackend una vez que confirma los datos le devuelve al usuario un token. A partir\nde entonces todas las peticiones HTTP del usuario deben ir acompañadas de este\ntoken(cabecera, queryString...). El token se almacena en el lado del cliente de\nalguna forma(sessionStorage o localStorage por ejemplo), lo que hace que no\ntenga que mantener esta información el backend, lo que convierte todo en\nbastante más escalable. El Token es una firma cifrada que el backend descifra y\nverifica al recibirla lo que permite confirmar la identidad del usuario.\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación\npara todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer\nla gestión pertinente del token. También nos provee de algo más de seguridad, ya\nque no usa cookies para mantener información de usuario se pueden evitar ciertos\ntipos de ataques que manipulen la sesión y además podemos hacer que el token\nexpire cada cierto tiempo lo que nos provee de otra capa más de seguridad.\nVamos a hablar un poco del token que recibimos para que entendamos un poco que\ninformación lleva. Este de aqui será un token tipo\n\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n\n\nSi os fijáis bien esta compuesto por tres strings separados por puntos, hablemos\nun poco de cada uno\n\n1º Header\n\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n\n\nEsto básicamente indica el tipo de token y el algoritmo usado para codificar,\nnormalmente es HMAC SHA256. Descodificado sería algo similar a esto:\n\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n\n\n2º Payload/Data\n\neyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n\n\nLa segunda parte tiene datos extra que indicamos nosotros desde el backend que\nse guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este \npayload a parte de la información que queramos nosotros guardar, tiene lo que se\nconoce como claims, son atributos propios que definen el token(aqui\n[http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName] \nmás en detalle), tiene mínimo 2:\n\n * iat: La fecha en la que se creó el token.\n * exp: La fecha de expiración del token. Esto normalmente lo indicamos nosotros\n   desde el backend.\n\nDescodificado este tendría:\n\n{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n\n\n3º Firma/Signature\n\nqVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n\n\nEsta última parte es la que realmente comprobamos en el backend, esta compuesta\nde los 2 strings anteriores codificados en BASE64 junto con una clave secreta \nque indicamos nosotros en el backend, por lo que si lo que descodifica en este\npunto es igual que lo anterior da por sentado que es correcto.\nDescodificado sería:\n\nHMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n\n\nSecret KEY es la clave secreta que hemos usado para codificar. Podemos comprobar\neste token completo en la pagina oficial de JWT.io [https://jwt.io/] solo es\nnecesario copiar el token completo en la parte donde pone ENCODED y poner la\nclave secreta \"Secret KEY\" en la zona donde pone VERIFY SIGNATURE.\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token,\nahora vamos a implantar JWT en Node para que veamos un ejemplo de como se hace\nimplanta.\n\nLo primero de todo como siempre es instalar el módulo de jsonwebtoken con npm.\n\nnpm install jsonwebtoken --save\n\n\nUna vez instalado, vamos a crearnos otra ruta para hacer el login (así repasamos\nun poco), para ello en la carpeta routes creamos el fichero login.js con este\ncontenido\n\nvar express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n\n\nComo siempre requerimos express e instanciamos router, como extra requerimos \nnuestro nuevo módulo jsonwebtoken\n\nconst express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nHacemos que este nuevo middleware responda a peticiones post, necesario ya que\nmandaremos la información en el body, y extraemos el usuario y contraseña para\ncomprobarlos(se podría hacer en el cliente que la contraseña se codificara de\nalguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con\nNode)\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n\nPonemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en\nnuestro caso que usuario y contraseña están bien, pero recordar que esto\nrealmente se debería comprobar en una base de datos o similar, esto es solo para\nagilizar el desarrollo\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n\n\nAhora tenemos donde creamos el token\n\nconst token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n\n\nLe hemos puesto un payload/data en formato JSON(da menos problemas con este\nformato) que contiene el usuario. Luego le hemos indicado la clave secreta para\ncomponer el hash Secret KEY, **IMPORTANTE esto no debería estar así deberíamos\nponerlo en un fichero de configuración o en las variables de entorno de nuestro\nbackend, para extraerlo con process.env... **. Por último le hemos indicado el\ntiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos\nen la página de npm sobre JSON Web token\n[https://www.npmjs.com/package/jsonwebtoken].\nPor último le devolvemos al cliente el token que hemos generado para que lo use\n\nres.json({sucess: true, token: token});\n\n\nYa tenemos nuestra nueva ruta creada, la indicamos en el app.js, importamos la\nnueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente\n\nvar ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n\n\nY le indicamos a express que la use(debajo de la de ninjas por ejemplo)\n\napp.use('/ninjas',ninjas);\napp.use('/login',login);\n\n\nVoilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un\nsoftware tipo POSTMAN o similar que nos permite personalizar como hacemos las\npeticiones HTTP.\nComo hemos configurado le pasamos en el body por post el usuario y contraseña.\n\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si\ncambiamos la contraseña veréis como nos devuelve algún tipo de 401\n\n\nBueno ya tenemos el token.....pero nos falta algún sitio para usarlo,\n¿no?...pues vamos a por ello.\nAl igual que hicimos arriba con Basic Auth vamos a crearnos un módulo para\ngestionar la verificación del login. En la carpeta lib creamos el fichero \nauthJWT.js y ponemos lo siguiente\n\nconst jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n\n\nEl código es bastante simple, recibimos el token por queryString, y lo\nverificamos con jwt.verify pasandole también la clave privada que hemos usado y\nuna vez comprobado saltaría el callback con el error o con el payload\ndescodificado. Recordar clave secreta aqui kaka, tiene que estar en fichero de\nconfiguración o en variable de entorno\n\njwt.verify(token,'Secret KEY',(err,decoded) => {\n\n\nLe he puesto un console.log para que veáis lo que descodifica si todo va bien o\nda error.\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En\neste caso vamos a cambiar el que usamos con Basic Auth y usamos el nuevo con JWT\n. Nos vamos a ninjas.js y ponemos lo siguiente\n\n'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n\n\nComentamos lo que pertenecia a basic-auth y hacemos lo mismo que hicimos antes\npero con JWT y ya lo tendríamos, vamos a probarlo para ello el token que nos ha\ndevuelto antes se lo pasamos como queryString\n\nhttp://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n\n\nY si todo va bien veremos esto\n\ny si por algún motivo el token no es correcto\n\nBueno como hemos visto usar JSON web Token es relativamente sencillo, en este\ncaso no hemos usado base de datos pero lo ideal seria tener los usuarios y\ncontraseñas almacenados en una base de datos, con la contraseña codificada con\nalgún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no\ntenerlos en nuestro código puestos a mano.\nComo extra comentaros que casi todos los métodos de autenticación con token\n(login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo)\nsuelen funcionar de forma similar, es decir un token que almacenamos y pasamos\nen cada petición normalmente en el header con un nombre tipo x-access-token, \nauthorization o similar.\n\nY hasta aquí la parte de autenticación en el siguiente post y el último por el\nmomento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos\nde Promesas que aunque no es propio de NodeJS, es más de JS creo que es útil que\nlas repasemos y también veremos como poner nuestro proceso de Node en cluster \npara aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una\nlinea nueva de post donde hablaremos de MongoDB y ya de paso lo integraremos con\nNode.\n\nNos veeeemossss un abrazooorrrrrr","html":"<!--kg-card-begin: markdown--><p>En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como <strong>Basic Auth</strong> y de <strong>JSON Web Token</strong>.</p>\n<h3 id=\"basicauth\">Basic Auth</h3>\n<p>Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) ).<br>\nVamos a configurar por ejemplo nuestra ruta con <em>heros</em>, la que está en el fichero <em>ninjas.js</em> para que nos solicite un usuario y contraseña.</p>\n<p>Lo primero de todo como es habitual en Node, usaremos <em>npm</em> para instalar el módulo necesario</p>\n<pre><code>npm install basic-auth --save\n</code></pre>\n<p>A continuación lo que hacemos es <em>requerir</em> el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos <em>requerido</em> y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella.</p>\n<pre><code>//Con esto importamos el módulo\nconst auth = require('basic-auth');\n</code></pre>\n<p>Y en nuestro middleware</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n</code></pre>\n<p>Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más.<br>\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante <strong>userLogin</strong>, con todo esto de momento nuestro código sería el siguiente</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:&quot;Somos un monton de ninjas autenticados&quot; })\n});\n</code></pre>\n<p>Si ahora lo probamos tendríamos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png\" alt=\"Http_Auth example1\"><br>\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos</p>\n<pre><code>router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:&quot;Somos un montón de ninjas autenticados&quot; })\n});\n</code></pre>\n<p>Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png\" alt=\"Http Auth success\"><br>\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el <strong>app.js</strong> y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general).<br>\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta <em>lib</em> que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero <strong>auth.js</strong> y lo que haremos será <em>exportar</em> el <em>callback</em> al que respondería un middleware</p>\n<pre><code>'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) =&gt; {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n</code></pre>\n<p>Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un <strong>next()</strong> para que continue con el siguiente middleware que coincida.<br>\nAhora vamos a módificar nuestra ruta <em>ninjas</em> para que use esto</p>\n<pre><code>'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:&quot;Somos un montón de ninjas autenticados&quot; })\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. <strong>A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando</strong>.<br>\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente.<br>\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico.</p>\n<h3 id=\"jsonwebtoken\">JSON Web Token</h3>\n<p>Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON.<br>\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un <em>token</em>. A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma(<em>sessionStorage o localStorage</em> por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El <em>Token</em> es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario.<br>\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad.<br>\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo</p>\n<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre>\n<p>Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno</p>\n<p><strong>1º Header</strong></p>\n<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n</code></pre>\n<p>Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es <em>HMAC SHA256</em>. Descodificado sería algo similar a esto:</p>\n<pre><code>{\n  &quot;alg&quot;: &quot;HS256&quot;,\n  &quot;typ&quot;: &quot;JWT&quot;\n}\n</code></pre>\n<p><strong>2º Payload/Data</strong></p>\n<pre><code>eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n</code></pre>\n<p>La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este <em>payload</em> a parte de la información que queramos nosotros guardar, tiene lo que se conoce como <em>claims</em>, son atributos propios que definen el token(<a href=\"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName\">aqui</a> más en detalle), tiene mínimo 2:</p>\n<ul>\n<li><em>iat</em>: La fecha en la que se creó el token.</li>\n<li><em>exp</em>: La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend.</li>\n</ul>\n<p>Descodificado este tendría:</p>\n<pre><code>{\n  &quot;user&quot;: &quot;ninja&quot;,\n  &quot;iat&quot;: 1506849851,\n  &quot;exp&quot;: 1507022651\n}\n</code></pre>\n<p><strong>3º Firma/Signature</strong></p>\n<pre><code>qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre>\n<p>Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en <em>BASE64</em> junto con una <em>clave secreta</em> que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto.<br>\nDescodificado sería:</p>\n<pre><code>HMACSHA256(\n  base64UrlEncode(header) + &quot;.&quot; +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n</code></pre>\n<p><em>Secret KEY</em> es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de <a href=\"https://jwt.io/\">JWT.io</a> solo es necesario copiar el token completo en la parte donde pone <em>ENCODED</em> y poner la clave secreta <em>&quot;Secret KEY&quot;</em> en la zona donde pone <em>VERIFY SIGNATURE</em>.<br>\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar <em>JWT</em> en <em>Node</em> para que veamos un ejemplo de como se hace implanta.</p>\n<p>Lo primero de todo como siempre es instalar el módulo de <em>jsonwebtoken</em> con npm.</p>\n<pre><code>npm install jsonwebtoken --save\n</code></pre>\n<p>Una vez instalado, vamos a crearnos otra <em>ruta</em> para hacer el login (así repasamos un poco), para ello en la carpeta <em>routes</em> creamos el fichero <em>login.js</em> con este contenido</p>\n<pre><code>var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: &quot;2 days&quot;});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Como siempre <em>requerimos</em> express e instanciamos <em>router</em>, como extra <em>requerimos</em> nuestro nuevo módulo <strong>jsonwebtoken</strong></p>\n<pre><code>const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n</code></pre>\n<p>Hacemos que este nuevo middleware responda a peticiones <em>post</em>, necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)</p>\n<pre><code>router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n</code></pre>\n<p>Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo</p>\n<pre><code>  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n</code></pre>\n<p>Ahora tenemos donde creamos el token</p>\n<pre><code>const token = jwt.sign({user: user},'Secret KEY',{expiresIn: &quot;2 days&quot;});\n</code></pre>\n<p>Le hemos puesto un <em>payload/data</em> en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash <em>Secret KEY</em>, **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con <em>process.env...</em> **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre <a href=\"https://www.npmjs.com/package/jsonwebtoken\">JSON Web token</a>.<br>\nPor último le devolvemos al cliente el token que hemos generado para que lo use</p>\n<pre><code>res.json({sucess: true, token: token});\n</code></pre>\n<p>Ya tenemos nuestra nueva ruta creada, la indicamos en el <em>app.js</em>, importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente</p>\n<pre><code>var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n</code></pre>\n<p>Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)</p>\n<pre><code>app.use('/ninjas',ninjas);\napp.use('/login',login);\n</code></pre>\n<p>Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo <em>POSTMAN</em> o similar que nos permite personalizar como hacemos las peticiones HTTP.<br>\nComo hemos configurado le pasamos en el <em>body por post</em> el usuario y contraseña.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png\" alt=\"Postman login\"><br>\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png\" alt=\"postman fail login\"></p>\n<p>Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello.<br>\nAl igual que hicimos arriba con <em>Basic Auth</em> vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta <em>lib</em> creamos el fichero <em>authJWT.js</em> y ponemos lo siguiente</p>\n<pre><code>const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) =&gt; {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n</code></pre>\n<p>El código es bastante simple, recibimos el token por <em>queryString</em>, y lo verificamos con <strong>jwt.verify</strong> pasandole también la <em>clave privada</em> que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. <strong>Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno</strong></p>\n<pre><code>jwt.verify(token,'Secret KEY',(err,decoded) =&gt; {\n</code></pre>\n<p>Le he puesto un <em>console.log</em> para que veáis lo que descodifica si todo va bien o da error.<br>\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con <em>Basic Auth</em> y usamos el nuevo con <em>JWT</em>. Nos vamos a <em>ninjas.js</em> y ponemos lo siguiente</p>\n<pre><code>'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:&quot;Somos un monton de ninjas autenticados&quot; })\n});\n\nmodule.exports = router;\n</code></pre>\n<p>Comentamos lo que pertenecia a <em>basic-auth</em> y hacemos lo mismo que hicimos antes pero con <em>JWT</em> y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como <em>queryString</em></p>\n<pre><code>http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n</code></pre>\n<p>Y si todo va bien veremos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png\" alt=\"Token success\"><br>\ny si por algún motivo el token no es correcto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png\" alt=\"Token error\"><br>\nBueno como hemos visto usar <em>JSON web Token</em> es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano.<br>\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el <strong>header</strong> con un nombre tipo <em>x-access-token</em>, <em>authorization</em> o similar.</p>\n<p>Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de <strong>Promesas</strong> que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en <strong>cluster</strong> para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de <strong>MongoDB</strong> y ya de paso lo integraremos con Node.</p>\n<p>Nos veeeemossss un abrazooorrrrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-x-templates-o-vistas-2/","canonical_url":null,"uuid":"96fce422-5da1-4ecd-99e6-8fc5f9d47d37","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59ce10cf58177700014ca379","reading_time":11,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como <strong>Basic Auth</strong> y de <strong>JSON Web Token</strong>.</p>\n<h3 id=\"basicauth\">Basic Auth</h3>\n<p>Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) ).<br>\nVamos a configurar por ejemplo nuestra ruta con <em>heros</em>, la que está en el fichero <em>ninjas.js</em> para que nos solicite un usuario y contraseña.</p>\n<p>Lo primero de todo como es habitual en Node, usaremos <em>npm</em> para instalar el módulo necesario</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install basic-auth --save\n</code></pre></div>\n<p>A continuación lo que hacemos es <em>requerir</em> el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos <em>requerido</em> y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Con esto importamos el módulo\nconst auth = require('basic-auth');\n</code></pre></div>\n<p>Y en nuestro middleware</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n</code></pre></div>\n<p>Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más.<br>\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante <strong>userLogin</strong>, con todo esto de momento nuestro código sería el siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n</code></pre></div>\n<p>Si ahora lo probamos tendríamos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png\" alt=\"Http_Auth example1\"><br>\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n</code></pre></div>\n<p>Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png\" alt=\"Http Auth success\"><br>\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el <strong>app.js</strong> y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general).<br>\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta <em>lib</em> que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero <strong>auth.js</strong> y lo que haremos será <em>exportar</em> el <em>callback</em> al que respondería un middleware</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n</code></pre></div>\n<p>Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un <strong>next()</strong> para que continue con el siguiente middleware que coincida.<br>\nAhora vamos a módificar nuestra ruta <em>ninjas</em> para que use esto</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. <strong>A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando</strong>.<br>\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente.<br>\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico.</p>\n<h3 id=\"jsonwebtoken\">JSON Web Token</h3>\n<p>Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON.<br>\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un <em>token</em>. A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma(<em>sessionStorage o localStorage</em> por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El <em>Token</em> es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario.<br>\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad.<br>\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre></div>\n<p>Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno</p>\n<p><strong>1º Header</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n</code></pre></div>\n<p>Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es <em>HMAC SHA256</em>. Descodificado sería algo similar a esto:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n</code></pre></div>\n<p><strong>2º Payload/Data</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n</code></pre></div>\n<p>La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este <em>payload</em> a parte de la información que queramos nosotros guardar, tiene lo que se conoce como <em>claims</em>, son atributos propios que definen el token(<a href=\"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName\">aqui</a> más en detalle), tiene mínimo 2:</p>\n<ul>\n<li><em>iat</em>: La fecha en la que se creó el token.</li>\n<li><em>exp</em>: La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend.</li>\n</ul>\n<p>Descodificado este tendría:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n</code></pre></div>\n<p><strong>3º Firma/Signature</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n</code></pre></div>\n<p>Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en <em>BASE64</em> junto con una <em>clave secreta</em> que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto.<br>\nDescodificado sería:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">HMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n</code></pre></div>\n<p><em>Secret KEY</em> es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de <a href=\"https://jwt.io/\">JWT.io</a> solo es necesario copiar el token completo en la parte donde pone <em>ENCODED</em> y poner la clave secreta <em>\"Secret KEY\"</em> en la zona donde pone <em>VERIFY SIGNATURE</em>.<br>\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar <em>JWT</em> en <em>Node</em> para que veamos un ejemplo de como se hace implanta.</p>\n<p>Lo primero de todo como siempre es instalar el módulo de <em>jsonwebtoken</em> con npm.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install jsonwebtoken --save\n</code></pre></div>\n<p>Una vez instalado, vamos a crearnos otra <em>ruta</em> para hacer el login (así repasamos un poco), para ello en la carpeta <em>routes</em> creamos el fichero <em>login.js</em> con este contenido</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Como siempre <em>requerimos</em> express e instanciamos <em>router</em>, como extra <em>requerimos</em> nuestro nuevo módulo <strong>jsonwebtoken</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n</code></pre></div>\n<p>Hacemos que este nuevo middleware responda a peticiones <em>post</em>, necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n</code></pre></div>\n<p>Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n</code></pre></div>\n<p>Ahora tenemos donde creamos el token</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n</code></pre></div>\n<p>Le hemos puesto un <em>payload/data</em> en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash <em>Secret KEY</em>, **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con <em>process.env...</em> **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre <a href=\"https://www.npmjs.com/package/jsonwebtoken\">JSON Web token</a>.<br>\nPor último le devolvemos al cliente el token que hemos generado para que lo use</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">res.json({sucess: true, token: token});\n</code></pre></div>\n<p>Ya tenemos nuestra nueva ruta creada, la indicamos en el <em>app.js</em>, importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n</code></pre></div>\n<p>Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app.use('/ninjas',ninjas);\napp.use('/login',login);\n</code></pre></div>\n<p>Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo <em>POSTMAN</em> o similar que nos permite personalizar como hacemos las peticiones HTTP.<br>\nComo hemos configurado le pasamos en el <em>body por post</em> el usuario y contraseña.<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png\" alt=\"Postman login\"><br>\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png\" alt=\"postman fail login\"></p>\n<p>Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello.<br>\nAl igual que hicimos arriba con <em>Basic Auth</em> vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta <em>lib</em> creamos el fichero <em>authJWT.js</em> y ponemos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n</code></pre></div>\n<p>El código es bastante simple, recibimos el token por <em>queryString</em>, y lo verificamos con <strong>jwt.verify</strong> pasandole también la <em>clave privada</em> que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. <strong>Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">jwt.verify(token,'Secret KEY',(err,decoded) => {\n</code></pre></div>\n<p>Le he puesto un <em>console.log</em> para que veáis lo que descodifica si todo va bien o da error.<br>\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con <em>Basic Auth</em> y usamos el nuevo con <em>JWT</em>. Nos vamos a <em>ninjas.js</em> y ponemos lo siguiente</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n</code></pre></div>\n<p>Comentamos lo que pertenecia a <em>basic-auth</em> y hacemos lo mismo que hicimos antes pero con <em>JWT</em> y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como <em>queryString</em></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n</code></pre></div>\n<p>Y si todo va bien veremos esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png\" alt=\"Token success\"><br>\ny si por algún motivo el token no es correcto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png\" alt=\"Token error\"><br>\nBueno como hemos visto usar <em>JSON web Token</em> es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano.<br>\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el <strong>header</strong> con un nombre tipo <em>x-access-token</em>, <em>authorization</em> o similar.</p>\n<p>Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de <strong>Promesas</strong> que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en <strong>cluster</strong> para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de <strong>MongoDB</strong> y ya de paso lo integraremos con Node.</p>\n<p>Nos veeeemossss un abrazooorrrrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" y de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"JSON Web Token"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"basicauth"},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) )."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a configurar por ejemplo nuestra ruta con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"heros"}]},{"type":"text","value":", la que está en el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" para que nos solicite un usuario y contraseña."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero de todo como es habitual en Node, usaremos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"npm"}]},{"type":"text","value":" para instalar el módulo necesario"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install basic-auth --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A continuación lo que hacemos es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerir"}]},{"type":"text","value":" el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerido"}]},{"type":"text","value":" y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"//Con esto importamos el módulo\nconst auth = require('basic-auth');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y en nuestro middleware"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"userLogin"}]},{"type":"text","value":", con todo esto de momento nuestro código sería el siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;//Esto para que no continue la ejecución del middleware\n    }\n    \n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ahora lo probamos tendríamos esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png","alt":"Http_Auth example1"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.get('/heros', function(req, res, next) {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png","alt":"Http Auth success"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":" y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general)."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"lib"}]},{"type":"text","value":" que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"auth.js"}]},{"type":"text","value":" y lo que haremos será "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"exportar"}]},{"type":"text","value":" el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"callback"}]},{"type":"text","value":" al que respondería un middleware"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict';\n\nconst auth = require('basic-auth');\n\nmodule.exports = (req, res, next) => {\n\n    const userLogin = auth(req);\n    \n    if (!userLogin) { \n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n\n    //Aqui haríamos la comprobación en nuestras base de datos o similar\n    if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){\n        res.set('WWW-Authenticate', 'basic realm=Authorization Required');\n        res.send(401);\n        return;\n    }\n    next();//Para que continue con el siguiente middleware\n\n};\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"next()"}]},{"type":"text","value":" para que continue con el siguiente middleware que coincida."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora vamos a módificar nuestra ruta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas"}]},{"type":"text","value":" para que use esto"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\nvar express = require('express');\nvar router = express.Router();\nconst auth = require('../lib/auth.js');\n\n/* GET home page. */\nrouter.get('/heros', auth, function(req, res, next) {\n\n    res.json({ninja:\"Somos un montón de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"jsonwebtoken"},"children":[{"type":"text","value":"JSON Web Token"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEl proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"token"}]},{"type":"text","value":". A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma("},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"sessionStorage o localStorage"}]},{"type":"text","value":" por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Token"}]},{"type":"text","value":" es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nEste tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"1º Header"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"HMAC SHA256"}]},{"type":"text","value":". Descodificado sería algo similar a esto:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"2º Payload/Data"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"payload"}]},{"type":"text","value":" a parte de la información que queramos nosotros guardar, tiene lo que se conoce como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"claims"}]},{"type":"text","value":", son atributos propios que definen el token("},{"type":"element","tagName":"a","properties":{"href":"http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName"},"children":[{"type":"text","value":"aqui"}]},{"type":"text","value":" más en detalle), tiene mínimo 2:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"iat"}]},{"type":"text","value":": La fecha en la que se creó el token."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"exp"}]},{"type":"text","value":": La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Descodificado este tendría:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"{\n  \"user\": \"ninja\",\n  \"iat\": 1506849851,\n  \"exp\": 1507022651\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"3º Firma/Signature"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"BASE64"}]},{"type":"text","value":" junto con una "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"clave secreta"}]},{"type":"text","value":" que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nDescodificado sería:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"HMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  Secret KEY\n)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Secret KEY"}]},{"type":"text","value":" es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de "},{"type":"element","tagName":"a","properties":{"href":"https://jwt.io/"},"children":[{"type":"text","value":"JWT.io"}]},{"type":"text","value":" solo es necesario copiar el token completo en la parte donde pone "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ENCODED"}]},{"type":"text","value":" y poner la clave secreta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"\"Secret KEY\""}]},{"type":"text","value":" en la zona donde pone "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"VERIFY SIGNATURE"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":" en "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":" para que veamos un ejemplo de como se hace implanta."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero de todo como siempre es instalar el módulo de "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"jsonwebtoken"}]},{"type":"text","value":" con npm."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"npm install jsonwebtoken --save\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Una vez instalado, vamos a crearnos otra "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ruta"}]},{"type":"text","value":" para hacer el login (así repasamos un poco), para ello en la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"routes"}]},{"type":"text","value":" creamos el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"login.js"}]},{"type":"text","value":" con este contenido"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var express = require('express');\nvar router = express.Router();\nconst jwt = require('jsonwebtoken')\n\n\nrouter.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n\n  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n   \n   //Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n   \n  //La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente\n  const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n  res.json({sucess: true, token: token});\n\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como siempre "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerimos"}]},{"type":"text","value":" express e instanciamos "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"router"}]},{"type":"text","value":", como extra "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"requerimos"}]},{"type":"text","value":" nuestro nuevo módulo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"jsonwebtoken"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const express = require('express');\nconst router = express.Router();\nconst jwt = require('jsonwebtoken')\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hacemos que este nuevo middleware responda a peticiones "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"post"}]},{"type":"text","value":", necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"router.post('/', function(req, res, next) {\n  \n  const user = req.body.user; \n  const pass = req.body.pass;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"  if (!user){\n      return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});\n  }\n\n  if (!pass){\n    return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});\n  }\n\n  if (user !== 'ninja' || pass !== '1234'){\n    return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});\n    \n  }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora tenemos donde creamos el token"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const token = jwt.sign({user: user},'Secret KEY',{expiresIn: \"2 days\"});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le hemos puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"payload/data"}]},{"type":"text","value":" en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Secret KEY"}]},{"type":"text","value":", **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"process.env..."}]},{"type":"text","value":" **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre "},{"type":"element","tagName":"a","properties":{"href":"https://www.npmjs.com/package/jsonwebtoken"},"children":[{"type":"text","value":"JSON Web token"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último le devolvemos al cliente el token que hemos generado para que lo use"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"res.json({sucess: true, token: token});\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ya tenemos nuestra nueva ruta creada, la indicamos en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"app.js"}]},{"type":"text","value":", importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"var ninjas = require('./routes/ninjas');\nvar login = require('./routes/login');\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"app.use('/ninjas',ninjas);\napp.use('/login',login);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"POSTMAN"}]},{"type":"text","value":" o similar que nos permite personalizar como hacemos las peticiones HTTP."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo hemos configurado le pasamos en el "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"body por post"}]},{"type":"text","value":" el usuario y contraseña."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png","alt":"Postman login"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png","alt":"postman fail login"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAl igual que hicimos arriba con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"lib"}]},{"type":"text","value":" creamos el fichero "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"authJWT.js"}]},{"type":"text","value":" y ponemos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"const jwt = require('jsonwebtoken');\n\nmodule.exports =  function(req,res,next) {\n        \n        const token = req.query.token;\n\n        if (token){\n            \n            jwt.verify(token,'Secret KEY',(err,decoded) => {\n                if (err){\n                    console.log(decoded)\n                    return res.status(401).json({success: false, error: 'Failed to authenticate token'});\n                } else {\n                    console.log('Decoded',decoded);\n                    next();\n                }\n            });\n\n        }else{\n            return res.status(403).json({success: false, error: 'No token provided'})\n        }\n    }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"El código es bastante simple, recibimos el token por "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"queryString"}]},{"type":"text","value":", y lo verificamos con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"jwt.verify"}]},{"type":"text","value":" pasandole también la "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"clave privada"}]},{"type":"text","value":" que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"jwt.verify(token,'Secret KEY',(err,decoded) => {\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Le he puesto un "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"console.log"}]},{"type":"text","value":" para que veáis lo que descodifica si todo va bien o da error."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Basic Auth"}]},{"type":"text","value":" y usamos el nuevo con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":". Nos vamos a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"ninjas.js"}]},{"type":"text","value":" y ponemos lo siguiente"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"'use strict'\n\nvar express = require('express');\nvar router = express.Router();\n//const auth = require('../lib/auth.js');\nconst authJWT = require('../lib/authJWT.js');\n\nrouter.get('/heros', authJWT, function(req, res, next) {\n\n    res.json({ninja:\"Somos un monton de ninjas autenticados\" })\n});\n\nmodule.exports = router;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Comentamos lo que pertenecia a "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"basic-auth"}]},{"type":"text","value":" y hacemos lo mismo que hicimos antes pero con "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JWT"}]},{"type":"text","value":" y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"queryString"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y si todo va bien veremos esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png","alt":"Token success"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\ny si por algún motivo el token no es correcto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png","alt":"Token error"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno como hemos visto usar "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"JSON web Token"}]},{"type":"text","value":" es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"header"}]},{"type":"text","value":" con un nombre tipo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"x-access-token"}]},{"type":"text","value":", "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"authorization"}]},{"type":"text","value":" o similar."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Promesas"}]},{"type":"text","value":" que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"cluster"}]},{"type":"text","value":" para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"MongoDB"}]},{"type":"text","value":" y ya de paso lo integraremos con Node."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos veeeemossss un abrazooorrrrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"basicauth","heading":"Basic Auth"},{"id":"jsonwebtoken","heading":"JSON Web Token"}]},"featureImageSharp":{"base":"nodebaner-6.jpg","publicURL":"/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-6.jpg","imageMeta":{"width":1680,"height":420},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAGrMokzQT//xAAXEAEBAQEAAAAAAAAAAAAAAAACASIh/9oACAEBAAEFAgMKdU1//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/AamP/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAECAQE/AV1//8QAFRABAQAAAAAAAAAAAAAAAAAAEHH/2gAIAQEABj8Cr//EABgQAQADAQAAAAAAAAAAAAAAAAEAETEh/9oACAEBAAE/Ido1iddq0QhE/9oADAMBAAIAAwAAABDz/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QbrNxf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgav/EABgQAQADAQAAAAAAAAAAAAAAAAEAETFx/9oACAEBAAE/ECLXUGFQ03NnlQ0Zc//Z","aspectRatio":3.977272727272727,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-6.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/477ba/nodebaner-6.jpg 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/06776/nodebaner-6.jpg 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/ea4ab/nodebaner-6.jpg 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/3055e/nodebaner-6.jpg 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/eff08/nodebaner-6.jpg 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner-6.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-6.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/9fca7/nodebaner-6.webp 175w,\n/static/ebae59fce798d71ce68bf2a304f1491f/37a4e/nodebaner-6.webp 350w,\n/static/ebae59fce798d71ce68bf2a304f1491f/89afa/nodebaner-6.webp 700w,\n/static/ebae59fce798d71ce68bf2a304f1491f/78e7a/nodebaner-6.webp 1050w,\n/static/ebae59fce798d71ce68bf2a304f1491f/03d34/nodebaner-6.webp 1400w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner-6.webp 1680w","sizes":"(max-width: 700px) 100vw, 700px"}}}}}]}},"pageContext":{"slug":"dont-stop-the-party-node-js-v","prev":"dont-stop-the-party-node-js-vi-modulos","next":"react-superhero-v-mobx","tag":"nodejs","limit":3,"skip":0,"primaryTagCount":13,"collectionPaths":{}}},
    "staticQueryHashes": ["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}