{
    "componentChunkName": "component---node-modules-gatsby-theme-try-ghost-src-templates-post-js",
    "path": "/dont-stop-the-party-node-js-iv-hablemos-un-poco-de-js-iii/",
    "result": {"data":{"ghostPost":{"id":"Ghost__Post__5a338158333e0f134c248f2d","title":"Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)","slug":"dont-stop-the-party-node-js-iv-hablemos-un-poco-de-js-iii","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/nodebaner.jpg","excerpt":"Herencia\nEn JavaScript también existe este concepto, con la ayuda de lo que hemos visto\nen el post anterior, los prototypes, para resumir un poco lo que hacemos es\nllamar al \"padre\" del cual queramos heredar(como si llamaramos a super en otros\nlenguajes) y le decimos que cambie su this(su contexto o instancia) por el\nnuestro junto con los parámetros que necesitemos.\nCreo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos\nun constructor y luego extenderemos de él.\n\nfunctio","custom_excerpt":null,"visibility":"public","created_at_pretty":"12 Sep 2017","published_at_pretty":"12 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-12T21:09:36.000+02:00","published_at":"2017-09-12T09:06:00.000+02:00","updated_at":"2018-01-22T09:51:52.000+01:00","meta_title":null,"meta_description":"Continuemos con nuestro repaso a algunos conceptos de JavaScript para poder entender y usar correctamente 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":"Herencia\nEn JavaScript también existe este concepto, con la ayuda de lo que hemos visto\nen el post anterior, los prototypes, para resumir un poco lo que hacemos es\nllamar al \"padre\" del cual queramos heredar(como si llamaramos a super en otros\nlenguajes) y le decimos que cambie su this(su contexto o instancia) por el\nnuestro junto con los parámetros que necesitemos.\nCreo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos\nun constructor y luego extenderemos de él.\n\nfunction Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n     }\n  }\n\n\nEste sería nuestro constructor, vamos a crear un elemento para ver que funciona\n\nvar mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n\n\nSi ejecutamos esto(recordar con node nombreFicheroJS), veríamos que funciona\n\n\nAhora vamos a crear otra función que herede de la primera, para ello nos valemos\ndel método que tienen todas las funciones call\n\nfunction Hero(alias){\n      Superhero.call(this, alias);\n  }\n\n\nComo véis le pasamos el this de nuestro método y le pasamos el parámetro de la\nfunción superhero.\nPor último añadimos a los prototipos de la función Hero, un nuevo Superhero para\nque realmente lo herede, y tras esto ya podriamos usar Hero con las propiedades\nde Superhero\n\nHero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n\n\nNuestro rorschach puede usar los mismos métodos que Superhero, y para\ncomprobarlo he vuesto unos cuantos logs que nos mostrarían cuales son los\nprototypes que tiene, y si es una instancia de cada uno de nuestros\nconstructores\n\n\nHerencia Múltiple\nPodemos simular herencia múltiple aprovechando lo que acabamos de hacer y usando\nel método assign, este método lo que hace es copiar las propiedades de un objeto\nen otro, con lo que el objeto destino puede usarlas como si fueran suyas.\nVeámoslo con un ejemplo continuando con lo anterior.\n\nLo primero vamos a crear otro constructor, en este caso SuperPowers()\n\nfunction SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n\n\nY a continuación lo que haremos será \"asignarle\" estas propiedades a nuestro \nrorschach\n\nObject.assign(rorschach, new SuperPowers());\n\n\nSimplemente tenemos que usar el método assign de Object y como parámetros le\npasamos la instancia del objeto destino y una instancia del objeto origen, en\neste caso con new SuperPowers()\n\nAhora simplemente podemos comprobar que realmente nuestro rorschach tiene las\npropiedades de SuperPowers\n\nrorschach.superStrength();\nrorschach.superSpeed();\n\n\nAdemás le añadiremos lo mismo que antes para comprobar si es una instancia de \nSuperPowers, quedando así todo el código\n\n//Herencia\n\nfunction Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n    }\n}\n  \nvar mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n  \n  //Herencia de superhero\nfunction Hero(alias){\n    Superhero.call(this, alias);\n}\n  \nHero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n\n//Herencia Múltiple\nfunction SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n\nObject.assign(rorschach, new SuperPowers());\n\n\nrorschach.superStrength();\nrorschach.superSpeed();\n\nconsole.log('Es una instancia de SuperPowers? ' + (rorschach instanceof SuperPowers));\n\n\nLo que nos daría este resultado\n\n\nAnda!!! Hay algo distinto verdad?? Nos dice que no es una instancia de \nSuperPowers...pero ¿por qué?.. Bueno en este caso es bastante simple, realmente\nlo que hacemos es una copia de propiedades de un elemento a otro, es decir,\nsería como si el constructor de nuestro rorschach hubiera tenido las mismas\npropiedades que SuperPowers.\n\nY hasta aquí el repaso de algunos elementos de JavasScript, a partir del próximo\npost ya empezaremos a ver NodeJS (Por fiiiiiin!!!! ;) )\n\nNos vemoooossssss, un abrazooooooorrrr","html":"<!--kg-card-begin: markdown--><h2 id=\"herencia\">Herencia</h2>\n<p>En JavaScript también existe este concepto, con la ayuda de lo que hemos visto en el post anterior, <strong>los prototypes</strong>, para resumir un poco lo que hacemos es llamar al <strong>&quot;padre&quot;</strong> del cual queramos heredar(como si llamaramos a super en otros lenguajes) y le decimos que cambie su <strong>this</strong>(su contexto o instancia) por el nuestro junto con los parámetros que necesitemos.<br>\nCreo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos un constructor y luego extenderemos de él.</p>\n<pre><code>function Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n     }\n  }\n</code></pre>\n<p>Este sería nuestro constructor, vamos a crear un elemento para ver que funciona</p>\n<pre><code>var mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n</code></pre>\n<p>Si ejecutamos esto(recordar con <strong>node nombreFicheroJS</strong>), veríamos que funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-12-at-21.43.50.png\" alt=\"Constructor example\"></p>\n<p>Ahora vamos a crear otra función que herede de la primera, para ello nos valemos del método que tienen todas las funciones <strong>call</strong></p>\n<pre><code>function Hero(alias){\n      Superhero.call(this, alias);\n  }\n</code></pre>\n<p>Como véis le pasamos el this de nuestro método y le pasamos el parámetro de la función superhero.<br>\nPor último añadimos a los prototipos de la función Hero, un nuevo <strong>Superhero</strong> para que realmente lo herede, y tras esto ya podriamos usar <strong>Hero</strong> con las propiedades de <strong>Superhero</strong></p>\n<pre><code>Hero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n</code></pre>\n<p>Nuestro <strong>rorschach</strong> puede usar los mismos métodos que <strong>Superhero</strong>, y para comprobarlo he vuesto unos cuantos logs que nos mostrarían cuales son los prototypes que tiene, y si es una instancia de cada uno de nuestros constructores<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-08.42.43.png\" alt=\"Herence check logs\"></p>\n<h2 id=\"herenciamltiple\">Herencia Múltiple</h2>\n<p>Podemos simular herencia múltiple aprovechando lo que acabamos de hacer y usando el método <strong>assign</strong>, este método lo que hace es copiar las propiedades de un objeto en otro, con lo que el objeto destino puede usarlas como si fueran suyas. Veámoslo con un ejemplo continuando con lo anterior.</p>\n<p>Lo primero vamos a crear otro constructor, en este caso <strong>SuperPowers()</strong></p>\n<pre><code>function SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n</code></pre>\n<p>Y a continuación lo que haremos será <strong>&quot;asignarle&quot;</strong> estas propiedades a nuestro <strong>rorschach</strong></p>\n<pre><code>Object.assign(rorschach, new SuperPowers());\n</code></pre>\n<p>Simplemente tenemos que usar el método <strong>assign</strong> de <strong>Object</strong> y como parámetros le pasamos la instancia del objeto destino y una instancia del objeto origen, en este caso con <strong>new SuperPowers()</strong></p>\n<p>Ahora simplemente podemos comprobar que realmente nuestro <strong>rorschach</strong> tiene las propiedades de <strong>SuperPowers</strong></p>\n<pre><code>rorschach.superStrength();\nrorschach.superSpeed();\n</code></pre>\n<p>Además le añadiremos lo mismo que antes para comprobar si es una instancia de <strong>SuperPowers</strong>, quedando así todo el código</p>\n<pre><code>//Herencia\n\nfunction Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n    }\n}\n  \nvar mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n  \n  //Herencia de superhero\nfunction Hero(alias){\n    Superhero.call(this, alias);\n}\n  \nHero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n\n//Herencia Múltiple\nfunction SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n\nObject.assign(rorschach, new SuperPowers());\n\n\nrorschach.superStrength();\nrorschach.superSpeed();\n\nconsole.log('Es una instancia de SuperPowers? ' + (rorschach instanceof SuperPowers));\n</code></pre>\n<p>Lo que nos daría este resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.00.25.png\" alt=\"Multiple Herence\"></p>\n<p>Anda!!! Hay algo distinto verdad?? Nos dice que no es una instancia de <strong>SuperPowers</strong>...pero ¿por qué?.. Bueno en este caso es bastante simple, realmente lo que hacemos es una copia de propiedades de un elemento a otro, es decir, sería como si el constructor de nuestro <strong>rorschach</strong> hubiera tenido las mismas propiedades que <strong>SuperPowers</strong>.</p>\n<p>Y hasta aquí el repaso de algunos elementos de JavasScript, a partir del próximo post ya empezaremos a ver <strong>NodeJS</strong> (Por fiiiiiin!!!! ;) )</p>\n<p>Nos vemoooossssss, un abrazooooooorrrr</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-iv-hablemos-un-poco-de-js-iii/","canonical_url":null,"uuid":"2605201f-0e02-4e51-bcd4-4a798ba06ba2","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59b830f06c31a60001f69f23","reading_time":3,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><h2 id=\"herencia\">Herencia</h2>\n<p>En JavaScript también existe este concepto, con la ayuda de lo que hemos visto en el post anterior, <strong>los prototypes</strong>, para resumir un poco lo que hacemos es llamar al <strong>\"padre\"</strong> del cual queramos heredar(como si llamaramos a super en otros lenguajes) y le decimos que cambie su <strong>this</strong>(su contexto o instancia) por el nuestro junto con los parámetros que necesitemos.<br>\nCreo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos un constructor y luego extenderemos de él.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n     }\n  }\n</code></pre></div>\n<p>Este sería nuestro constructor, vamos a crear un elemento para ver que funciona</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n</code></pre></div>\n<p>Si ejecutamos esto(recordar con <strong>node nombreFicheroJS</strong>), veríamos que funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-12-at-21.43.50.png\" alt=\"Constructor example\"></p>\n<p>Ahora vamos a crear otra función que herede de la primera, para ello nos valemos del método que tienen todas las funciones <strong>call</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function Hero(alias){\n      Superhero.call(this, alias);\n  }\n</code></pre></div>\n<p>Como véis le pasamos el this de nuestro método y le pasamos el parámetro de la función superhero.<br>\nPor último añadimos a los prototipos de la función Hero, un nuevo <strong>Superhero</strong> para que realmente lo herede, y tras esto ya podriamos usar <strong>Hero</strong> con las propiedades de <strong>Superhero</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Hero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n</code></pre></div>\n<p>Nuestro <strong>rorschach</strong> puede usar los mismos métodos que <strong>Superhero</strong>, y para comprobarlo he vuesto unos cuantos logs que nos mostrarían cuales son los prototypes que tiene, y si es una instancia de cada uno de nuestros constructores<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-08.42.43.png\" alt=\"Herence check logs\"></p>\n<h2 id=\"herenciamltiple\">Herencia Múltiple</h2>\n<p>Podemos simular herencia múltiple aprovechando lo que acabamos de hacer y usando el método <strong>assign</strong>, este método lo que hace es copiar las propiedades de un objeto en otro, con lo que el objeto destino puede usarlas como si fueran suyas. Veámoslo con un ejemplo continuando con lo anterior.</p>\n<p>Lo primero vamos a crear otro constructor, en este caso <strong>SuperPowers()</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n</code></pre></div>\n<p>Y a continuación lo que haremos será <strong>\"asignarle\"</strong> estas propiedades a nuestro <strong>rorschach</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Object.assign(rorschach, new SuperPowers());\n</code></pre></div>\n<p>Simplemente tenemos que usar el método <strong>assign</strong> de <strong>Object</strong> y como parámetros le pasamos la instancia del objeto destino y una instancia del objeto origen, en este caso con <strong>new SuperPowers()</strong></p>\n<p>Ahora simplemente podemos comprobar que realmente nuestro <strong>rorschach</strong> tiene las propiedades de <strong>SuperPowers</strong></p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">rorschach.superStrength();\nrorschach.superSpeed();\n</code></pre></div>\n<p>Además le añadiremos lo mismo que antes para comprobar si es una instancia de <strong>SuperPowers</strong>, quedando así todo el código</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Herencia\n\nfunction Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n    }\n}\n  \nvar mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n  \n  //Herencia de superhero\nfunction Hero(alias){\n    Superhero.call(this, alias);\n}\n  \nHero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n\n//Herencia Múltiple\nfunction SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n\nObject.assign(rorschach, new SuperPowers());\n\n\nrorschach.superStrength();\nrorschach.superSpeed();\n\nconsole.log('Es una instancia de SuperPowers? ' + (rorschach instanceof SuperPowers));\n</code></pre></div>\n<p>Lo que nos daría este resultado<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.00.25.png\" alt=\"Multiple Herence\"></p>\n<p>Anda!!! Hay algo distinto verdad?? Nos dice que no es una instancia de <strong>SuperPowers</strong>...pero ¿por qué?.. Bueno en este caso es bastante simple, realmente lo que hacemos es una copia de propiedades de un elemento a otro, es decir, sería como si el constructor de nuestro <strong>rorschach</strong> hubiera tenido las mismas propiedades que <strong>SuperPowers</strong>.</p>\n<p>Y hasta aquí el repaso de algunos elementos de JavasScript, a partir del próximo post ya empezaremos a ver <strong>NodeJS</strong> (Por fiiiiiin!!!! ;) )</p>\n<p>Nos vemoooossssss, un abrazooooooorrrr</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"h2","properties":{"id":"herencia"},"children":[{"type":"text","value":"Herencia"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En JavaScript también existe este concepto, con la ayuda de lo que hemos visto en el post anterior, "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"los prototypes"}]},{"type":"text","value":", para resumir un poco lo que hacemos es llamar al "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"\"padre\""}]},{"type":"text","value":" del cual queramos heredar(como si llamaramos a super en otros lenguajes) y le decimos que cambie su "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"this"}]},{"type":"text","value":"(su contexto o instancia) por el nuestro junto con los parámetros que necesitemos."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nCreo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos un constructor y luego extenderemos de él."}]},{"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 Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n     }\n  }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Este sería nuestro constructor, vamos a crear un elemento para ver que funciona"}]},{"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 mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ejecutamos esto(recordar con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"node nombreFicheroJS"}]},{"type":"text","value":"), veríamos que 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-12-at-21.43.50.png","alt":"Constructor example"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora vamos a crear otra función que herede de la primera, para ello nos valemos del método que tienen todas las funciones "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"call"}]}]},{"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 Hero(alias){\n      Superhero.call(this, alias);\n  }\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como véis le pasamos el this de nuestro método y le pasamos el parámetro de la función superhero."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último añadimos a los prototipos de la función Hero, un nuevo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Superhero"}]},{"type":"text","value":" para que realmente lo herede, y tras esto ya podriamos usar "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Hero"}]},{"type":"text","value":" con las propiedades de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Superhero"}]}]},{"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":"Hero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"rorschach"}]},{"type":"text","value":" puede usar los mismos métodos que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Superhero"}]},{"type":"text","value":", y para comprobarlo he vuesto unos cuantos logs que nos mostrarían cuales son los prototypes que tiene, y si es una instancia de cada uno de nuestros constructores"},{"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-08.42.43.png","alt":"Herence check logs"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{"id":"herenciamltiple"},"children":[{"type":"text","value":"Herencia Múltiple"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Podemos simular herencia múltiple aprovechando lo que acabamos de hacer y usando el método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"assign"}]},{"type":"text","value":", este método lo que hace es copiar las propiedades de un objeto en otro, con lo que el objeto destino puede usarlas como si fueran suyas. Veámoslo con un ejemplo continuando con lo anterior."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo primero vamos a crear otro constructor, en este caso "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"SuperPowers()"}]}]},{"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 SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y a continuación lo que haremos será "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"\"asignarle\""}]},{"type":"text","value":" estas propiedades a nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"rorschach"}]}]},{"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":"Object.assign(rorschach, new SuperPowers());\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Simplemente tenemos que usar el método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"assign"}]},{"type":"text","value":" de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Object"}]},{"type":"text","value":" y como parámetros le pasamos la instancia del objeto destino y una instancia del objeto origen, en este caso con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"new SuperPowers()"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora simplemente podemos comprobar que realmente nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"rorschach"}]},{"type":"text","value":" tiene las propiedades de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"SuperPowers"}]}]},{"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":"rorschach.superStrength();\nrorschach.superSpeed();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Además le añadiremos lo mismo que antes para comprobar si es una instancia de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"SuperPowers"}]},{"type":"text","value":", quedando así todo el 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":"//Herencia\n\nfunction Superhero(alias) {\n    this.alias = alias;\n    this.getInfo = function () {\n       console.log('Nuestro héroe se llama ' + this.alias);\n    }\n}\n  \nvar mr_manhattan = new Superhero('Dr. Manhattan');\n \nmr_manhattan.getInfo();\n  \n  //Herencia de superhero\nfunction Hero(alias){\n    Superhero.call(this, alias);\n}\n  \nHero.prototype = new Superhero('Walter Joseph Kovacs');\n  \nvar rorschach = new Hero('Rorschach');\n  \nrorschach.getInfo();\n\nconsole.log(Object.getPrototypeOf(rorschach))\nconsole.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))\nconsole.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))\n\n//Herencia Múltiple\nfunction SuperPowers(){\n    this.superStrength = function(){\n        console.log( this.alias + ' tiene super fuerza')\n    }\n    this.superSpeed = function(){\n        console.log( this.alias + ' tiene super velocidad')\n    }\n}\n\nObject.assign(rorschach, new SuperPowers());\n\n\nrorschach.superStrength();\nrorschach.superSpeed();\n\nconsole.log('Es una instancia de SuperPowers? ' + (rorschach instanceof SuperPowers));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo que nos daría este resultado"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.00.25.png","alt":"Multiple Herence"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Anda!!! Hay algo distinto verdad?? Nos dice que no es una instancia de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"SuperPowers"}]},{"type":"text","value":"...pero ¿por qué?.. Bueno en este caso es bastante simple, realmente lo que hacemos es una copia de propiedades de un elemento a otro, es decir, sería como si el constructor de nuestro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"rorschach"}]},{"type":"text","value":" hubiera tenido las mismas propiedades que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"SuperPowers"}]},{"type":"text","value":"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y hasta aquí el repaso de algunos elementos de JavasScript, a partir del próximo post ya empezaremos a ver "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":" (Por fiiiiiin!!!! ;) )"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Nos vemoooossssss, un abrazooooooorrrr"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"herencia","heading":"Herencia"},{"id":"herenciamltiple","heading":"Herencia Múltiple"}]},"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":4,"src":"/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner.jpg","srcSet":"/static/ebae59fce798d71ce68bf2a304f1491f/65d8c/nodebaner.jpg 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/c5f21/nodebaner.jpg 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/d5c54/nodebaner.jpg 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/81a53/nodebaner.jpg 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/34c3a/nodebaner.jpg 1680w","srcWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner.webp","srcSetWebp":"/static/ebae59fce798d71ce68bf2a304f1491f/dc8f3/nodebaner.webp 260w,\n/static/ebae59fce798d71ce68bf2a304f1491f/2db4b/nodebaner.webp 520w,\n/static/ebae59fce798d71ce68bf2a304f1491f/e4875/nodebaner.webp 1040w,\n/static/ebae59fce798d71ce68bf2a304f1491f/f5845/nodebaner.webp 1560w,\n/static/ebae59fce798d71ce68bf2a304f1491f/41aa5/nodebaner.webp 1680w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"prev":{"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"}}}},"next":{"id":"Ghost__Post__5a338158333e0f134c248f29","title":"React Superhero (IV): Estructura de proyecto base","slug":"react-superhero-iv","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Captain-Atom.jpg","excerpt":"En el post anterior creamos un proyecto de React usando el CLI que nos\nproporcionan los creadores del mismo. Esta herramienta de linea de comandos nos\ncrea un proyecto base desde el que partir y como vimos cuando usamos npm start \npara arrancar nuestro servidor de desarrollo, la herramienta nos muestra una\npágina similar a esta:\n\n\n\nVeamos un poco la estructura del proyecto y desde donde podemos empezar a\ntrabajar.\nLo primero veamos lo que tenemos:\n\n\nEn lo primero que nos tenemos que fijar es en ","custom_excerpt":null,"visibility":"public","created_at_pretty":"4 Sep 2017","published_at_pretty":"7 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-09-04T09:21:09.000+02:00","published_at":"2017-09-07T10:26:00.000+02:00","updated_at":"2018-01-22T09:54:03.000+01:00","meta_title":null,"meta_description":"Veamos la estructura básica de proyecto que se nos crea cuando utilizamos el CLI para crear proyectos de ReactJS","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 el post anterior creamos un proyecto de React usando el CLI que nos\nproporcionan los creadores del mismo. Esta herramienta de linea de comandos nos\ncrea un proyecto base desde el que partir y como vimos cuando usamos npm start \npara arrancar nuestro servidor de desarrollo, la herramienta nos muestra una\npágina similar a esta:\n\n\n\nVeamos un poco la estructura del proyecto y desde donde podemos empezar a\ntrabajar.\nLo primero veamos lo que tenemos:\n\n\nEn lo primero que nos tenemos que fijar es en los index tanto el js, como el \nhtml, ya que son desde donde se empieza a llamar al resto. Si miramos el \nindex.html tenemos una pagina html con varios tags pero lo que nos importa\nrealmente es algo que ya hemos visto:\n\n <div id=\"root\"></div>\n\n\nRecordemos que es en ese punto donde se empieza a componer nuestra aplicación.\n\nLo siguiente miremos dentro de la carpeta src y veamos el index.js que aqui\ntenemos varias cosas interesantes:\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\n\n\nReactDOM.render(<App />, document.getElementById('root'));\nregisterServiceWorker();\n\n\nTenemos varios imports, luego el típico ReactDOM.render y por último una llamada\na un método registerServiceWorker(). Comencemos con los imports, los dos\nprimeros ya los hemos visto antes, son los específicos para que React funcione,\nveamos los siguientes:\n\n * \"import './index.css';\": No es muy especial solo importa el css, ni más ni\n   menos.\n * \"import App from './App';\" : Este import nos instancia el componente que está\n   dentro del fichero App.js, un poco más abajo hablaremos como está creado\n   esto, es algo parecido a node con los exports ;).\n * \"import registerServiceWorker from './registerServiceWorker';\": Este import\n   realemente es el que instancia el servidor local y anda pendiente de los\n   cambios en el código, lo que hace es cargar el export por defecto. Si alguién\n   tiene dudas con el código de este fichero que lo ponga en comentarios y lo\n   vemos ;).\n\nA continuación como ya hemos comentado, tenemos nuestro típico render de react\nque lo que hace es instanciar el componente App. Si miramos el código de App.js:\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          To get started, edit <code>src/App.js</code> and save to reload.\n        </p>\n      </div>\n    );\n  }\n}\n\nexport default App;\n\n\nVemos que ya hemos visto muchas cosas, comentar que los imports de logo y de \nApp.css los necesitamos para usarlos en nuestro código JSX, si os fijáis en la\nlínea:\n\n<img src={logo} className=\"App-logo\" alt=\"logo\" />\n\n\nTenemos las dos cosas, usamos el logo dentro de src y ya estamos usando tambien\nnombres de clases del fichero css.\n\nEn este punto faltaría solo comentar la última y casi la más importante del\nconjunto (en este punto jejeje):\n\nexport default App;\n\n\nEsta línea lo que indica es que por defecto cuando se haga un import de este\nfichero se importe el componente App. Un detalle importante, sin export no\nimportamos nada, si comentáramos esa línea tendríamos este resultado:\n\n\n\nCreo que más o menos se entiende todo, solo comentar que si quisieramos cambiar\nel componente App por otro solo tendríamos que crear el componente como queramos\nponerle la línea export y cambiar el dentro del ReactDOM.render como ya hemos\nvisto en algún post anterior (de todas formas iremos trabajando con esto más de\nuna vez ;) ).\n\nComo vemos prácticamente todo lo haremos dentro de la carpeta src y sigue\nmanteniendo el nivel de sencillez que hemos estado viendo.\n\nSin mucho más nos vemos en el siguiente. Un abrazoooooooo","html":"<!--kg-card-begin: markdown--><p>En el post anterior creamos un proyecto de <strong>React</strong> usando el <strong>CLI</strong> que nos proporcionan los creadores del mismo. Esta herramienta de linea de comandos nos crea un proyecto base desde el que partir y como vimos cuando usamos <strong>npm start</strong> para arrancar nuestro servidor de desarrollo, la herramienta nos muestra una página similar a esta:</p>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.26.57.png\" alt=\"React base page\"></p>\n<p>Veamos un poco la estructura del proyecto y desde donde podemos empezar a trabajar.<br>\nLo primero veamos lo que tenemos:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.29.33.png\" alt=\"Folders Base Project\"></p>\n<p>En lo primero que nos tenemos que fijar es en los <strong>index</strong> tanto el <strong>js</strong>, como el <strong>html</strong>, ya que son desde donde se empieza a llamar al resto. Si miramos el <strong>index.html</strong> tenemos una pagina html con varios tags pero lo que nos importa realmente es algo que ya hemos visto:</p>\n<pre><code> &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;\n</code></pre>\n<p>Recordemos que es en ese punto donde se empieza a componer nuestra aplicación.</p>\n<p>Lo siguiente miremos dentro de la carpeta <strong>src</strong> y veamos el <strong>index.js</strong> que aqui tenemos varias cosas interesantes:</p>\n<pre><code>import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\n\n\nReactDOM.render(&lt;App /&gt;, document.getElementById('root'));\nregisterServiceWorker();\n</code></pre>\n<p>Tenemos varios imports, luego el típico <strong>ReactDOM.render</strong> y por último una llamada a un método <strong>registerServiceWorker()</strong>. Comencemos con los <strong>imports</strong>, los dos primeros ya los hemos visto antes, son los específicos para que React funcione, veamos los siguientes:</p>\n<ul>\n<li><strong>&quot;import './index.css';&quot;</strong>: No es muy especial solo importa el css, ni más ni menos.</li>\n<li><strong>&quot;import App from './App';&quot;</strong> : Este import nos instancia el componente que está dentro del fichero <strong>App.js</strong>, un poco más abajo hablaremos como está creado esto, es algo parecido a node con los exports ;).</li>\n<li><strong>&quot;import registerServiceWorker from './registerServiceWorker';&quot;</strong>: Este import realemente es el que instancia el servidor local y anda pendiente de los cambios en el código, lo que hace es cargar el export por defecto. Si alguién tiene dudas con el código de este fichero que lo ponga en comentarios y lo vemos ;).</li>\n</ul>\n<p>A continuación como ya hemos comentado, tenemos nuestro típico render de react que lo que hace es instanciar el componente <strong>App</strong>. Si miramos el código de <strong>App.js</strong>:</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          To get started, edit &lt;code&gt;src/App.js&lt;/code&gt; and save to reload.\n        &lt;/p&gt;\n      &lt;/div&gt;\n    );\n  }\n}\n\nexport default App;\n</code></pre>\n<p>Vemos que ya hemos visto muchas cosas, comentar que los imports de <strong>logo</strong> y de <strong>App.css</strong> los necesitamos para usarlos en nuestro código JSX, si os fijáis en la línea:</p>\n<pre><code>&lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;\n</code></pre>\n<p>Tenemos las dos cosas, usamos el <strong>logo</strong> dentro de src y ya estamos usando tambien nombres de clases del fichero css.</p>\n<p>En este punto faltaría solo comentar la última y casi la más importante del conjunto (en este punto jejeje):</p>\n<pre><code>export default App;\n</code></pre>\n<p>Esta línea lo que indica es que por defecto cuando se haga un import de este fichero se importe el componente <strong>App</strong>. Un detalle importante, <strong>sin export no importamos nada</strong>, si comentáramos esa línea tendríamos este resultado:</p>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-21.42.51.png\" alt=\"Screen-Shot-2017-09-04-at-21.42.51\"></p>\n<p>Creo que más o menos se entiende todo, solo comentar que si quisieramos cambiar el componente <strong>App</strong> por otro solo tendríamos que crear el componente como queramos ponerle la línea <strong>export</strong> y cambiar el <strong><App /></strong> dentro del <strong>ReactDOM.render</strong> como ya hemos visto en algún post anterior (de todas formas iremos trabajando con esto más de una vez ;) ).</p>\n<p>Como vemos prácticamente todo lo haremos dentro de la carpeta <strong>src</strong> y sigue manteniendo el nivel de sencillez que hemos estado viendo.</p>\n<p>Sin mucho más nos vemos en el siguiente. Un abrazoooooooo</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/react-superhero-iv/","canonical_url":null,"uuid":"a12fcedc-92c4-4094-a631-9144bc91e900","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"59acfee5c5286700019db1d5","reading_time":3,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>En el post anterior creamos un proyecto de <strong>React</strong> usando el <strong>CLI</strong> que nos proporcionan los creadores del mismo. Esta herramienta de linea de comandos nos crea un proyecto base desde el que partir y como vimos cuando usamos <strong>npm start</strong> para arrancar nuestro servidor de desarrollo, la herramienta nos muestra una página similar a esta:</p>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.26.57.png\" alt=\"React base page\"></p>\n<p>Veamos un poco la estructura del proyecto y desde donde podemos empezar a trabajar.<br>\nLo primero veamos lo que tenemos:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.29.33.png\" alt=\"Folders Base Project\"></p>\n<p>En lo primero que nos tenemos que fijar es en los <strong>index</strong> tanto el <strong>js</strong>, como el <strong>html</strong>, ya que son desde donde se empieza a llamar al resto. Si miramos el <strong>index.html</strong> tenemos una pagina html con varios tags pero lo que nos importa realmente es algo que ya hemos visto:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"> &#x3C;div id=\"root\">&#x3C;/div>\n</code></pre></div>\n<p>Recordemos que es en ese punto donde se empieza a componer nuestra aplicación.</p>\n<p>Lo siguiente miremos dentro de la carpeta <strong>src</strong> y veamos el <strong>index.js</strong> que aqui tenemos varias cosas interesantes:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\n\n\nReactDOM.render(&#x3C;App />, document.getElementById('root'));\nregisterServiceWorker();\n</code></pre></div>\n<p>Tenemos varios imports, luego el típico <strong>ReactDOM.render</strong> y por último una llamada a un método <strong>registerServiceWorker()</strong>. Comencemos con los <strong>imports</strong>, los dos primeros ya los hemos visto antes, son los específicos para que React funcione, veamos los siguientes:</p>\n<ul>\n<li><strong>\"import './index.css';\"</strong>: No es muy especial solo importa el css, ni más ni menos.</li>\n<li><strong>\"import App from './App';\"</strong> : Este import nos instancia el componente que está dentro del fichero <strong>App.js</strong>, un poco más abajo hablaremos como está creado esto, es algo parecido a node con los exports ;).</li>\n<li><strong>\"import registerServiceWorker from './registerServiceWorker';\"</strong>: Este import realemente es el que instancia el servidor local y anda pendiente de los cambios en el código, lo que hace es cargar el export por defecto. Si alguién tiene dudas con el código de este fichero que lo ponga en comentarios y lo vemos ;).</li>\n</ul>\n<p>A continuación como ya hemos comentado, tenemos nuestro típico render de react que lo que hace es instanciar el componente <strong>App</strong>. Si miramos el código de <strong>App.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';\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          To get started, edit &#x3C;code>src/App.js&#x3C;/code> and save to reload.\n        &#x3C;/p>\n      &#x3C;/div>\n    );\n  }\n}\n\nexport default App;\n</code></pre></div>\n<p>Vemos que ya hemos visto muchas cosas, comentar que los imports de <strong>logo</strong> y de <strong>App.css</strong> los necesitamos para usarlos en nuestro código JSX, si os fijáis en la línea:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&#x3C;img src={logo} className=\"App-logo\" alt=\"logo\" />\n</code></pre></div>\n<p>Tenemos las dos cosas, usamos el <strong>logo</strong> dentro de src y ya estamos usando tambien nombres de clases del fichero css.</p>\n<p>En este punto faltaría solo comentar la última y casi la más importante del conjunto (en este punto jejeje):</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">export default App;\n</code></pre></div>\n<p>Esta línea lo que indica es que por defecto cuando se haga un import de este fichero se importe el componente <strong>App</strong>. Un detalle importante, <strong>sin export no importamos nada</strong>, si comentáramos esa línea tendríamos este resultado:</p>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-21.42.51.png\" alt=\"Screen-Shot-2017-09-04-at-21.42.51\"></p>\n<p>Creo que más o menos se entiende todo, solo comentar que si quisieramos cambiar el componente <strong>App</strong> por otro solo tendríamos que crear el componente como queramos ponerle la línea <strong>export</strong> y cambiar el <strong><app></app></strong> dentro del <strong>ReactDOM.render</strong> como ya hemos visto en algún post anterior (de todas formas iremos trabajando con esto más de una vez ;) ).</p>\n<p>Como vemos prácticamente todo lo haremos dentro de la carpeta <strong>src</strong> y sigue manteniendo el nivel de sencillez que hemos estado viendo.</p>\n<p>Sin mucho más nos vemos en el siguiente. Un abrazoooooooo</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En el post anterior creamos un proyecto de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"React"}]},{"type":"text","value":" usando el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"CLI"}]},{"type":"text","value":" que nos proporcionan los creadores del mismo. Esta herramienta de linea de comandos nos crea un proyecto base desde el que partir y como vimos cuando usamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"npm start"}]},{"type":"text","value":" para arrancar nuestro servidor de desarrollo, la herramienta nos muestra una página similar a esta:"}]},{"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-04-at-09.26.57.png","alt":"React base page"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Veamos un poco la estructura del proyecto y desde donde podemos empezar a trabajar."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nLo primero veamos lo que tenemos:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.29.33.png","alt":"Folders Base Project"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En lo primero que nos tenemos que fijar es en los "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index"}]},{"type":"text","value":" tanto el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"js"}]},{"type":"text","value":", como el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"html"}]},{"type":"text","value":", ya que son desde donde se empieza a llamar al resto. Si miramos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.html"}]},{"type":"text","value":" tenemos una pagina html con varios tags pero lo que nos importa realmente es algo que ya hemos visto:"}]},{"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":" <div id=\"root\"></div>\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Recordemos que es en ese punto donde se empieza a componer nuestra aplicación."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Lo siguiente miremos dentro de la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"src"}]},{"type":"text","value":" y veamos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"index.js"}]},{"type":"text","value":" que aqui tenemos varias cosas interesantes:"}]},{"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 from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\n\n\nReactDOM.render(<App />, document.getElementById('root'));\nregisterServiceWorker();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tenemos varios imports, luego el típico "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ReactDOM.render"}]},{"type":"text","value":" y por último una llamada a un método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"registerServiceWorker()"}]},{"type":"text","value":". Comencemos con los "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"imports"}]},{"type":"text","value":", los dos primeros ya los hemos visto antes, son los específicos para que React funcione, veamos los siguientes:"}]},{"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":"\"import './index.css';\""}]},{"type":"text","value":": No es muy especial solo importa el css, ni más ni menos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"\"import App from './App';\""}]},{"type":"text","value":" : Este import nos instancia el componente que está dentro del fichero "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.js"}]},{"type":"text","value":", un poco más abajo hablaremos como está creado esto, es algo parecido a node con los exports ;)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"\"import registerServiceWorker from './registerServiceWorker';\""}]},{"type":"text","value":": Este import realemente es el que instancia el servidor local y anda pendiente de los cambios en el código, lo que hace es cargar el export por defecto. Si alguién tiene dudas con el código de este fichero que lo ponga en comentarios y lo vemos ;)."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A continuación como ya hemos comentado, tenemos nuestro típico render de react que lo que hace es instanciar el componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App"}]},{"type":"text","value":". Si miramos el código de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.js"}]},{"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":"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          To get started, edit <code>src/App.js</code> and save to reload.\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":"Vemos que ya hemos visto muchas cosas, comentar que los imports de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"logo"}]},{"type":"text","value":" y de "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App.css"}]},{"type":"text","value":" los necesitamos para usarlos en nuestro código JSX, si os fijáis en la línea:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"<img src={logo} className=\"App-logo\" alt=\"logo\" />\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Tenemos las dos cosas, usamos el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"logo"}]},{"type":"text","value":" dentro de src y ya estamos usando tambien nombres de clases del fichero css."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"En este punto faltaría solo comentar la última y casi la más importante del conjunto (en este punto jejeje):"}]},{"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":"export default App;\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esta línea lo que indica es que por defecto cuando se haga un import de este fichero se importe el componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App"}]},{"type":"text","value":". Un detalle importante, "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"sin export no importamos nada"}]},{"type":"text","value":", si comentáramos esa línea tendríamos este resultado:"}]},{"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-04-at-21.42.51.png","alt":"Screen-Shot-2017-09-04-at-21.42.51"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Creo que más o menos se entiende todo, solo comentar que si quisieramos cambiar el componente "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"App"}]},{"type":"text","value":" por otro solo tendríamos que crear el componente como queramos ponerle la línea "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"export"}]},{"type":"text","value":" y cambiar el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"app","properties":{},"children":[]}]},{"type":"text","value":" dentro del "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ReactDOM.render"}]},{"type":"text","value":" como ya hemos visto en algún post anterior (de todas formas iremos trabajando con esto más de una vez ;) )."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como vemos prácticamente todo lo haremos dentro de la carpeta "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"src"}]},{"type":"text","value":" y sigue manteniendo el nivel de sencillez que hemos estado viendo."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Sin mucho más nos vemos en el siguiente. Un abrazoooooooo"}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[]},"featureImageSharp":{"base":"Captain-Atom.jpg","publicURL":"/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.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.jpg","srcSet":"/static/ea41313c22f611d45d277d453c4273d1/477ba/Captain-Atom.jpg 175w,\n/static/ea41313c22f611d45d277d453c4273d1/06776/Captain-Atom.jpg 350w,\n/static/ea41313c22f611d45d277d453c4273d1/ea4ab/Captain-Atom.jpg 700w,\n/static/ea41313c22f611d45d277d453c4273d1/fc1a6/Captain-Atom.jpg 864w","srcWebp":"/static/ea41313c22f611d45d277d453c4273d1/89afa/Captain-Atom.webp","srcSetWebp":"/static/ea41313c22f611d45d277d453c4273d1/9fca7/Captain-Atom.webp 175w,\n/static/ea41313c22f611d45d277d453c4273d1/37a4e/Captain-Atom.webp 350w,\n/static/ea41313c22f611d45d277d453c4273d1/89afa/Captain-Atom.webp 700w,\n/static/ea41313c22f611d45d277d453c4273d1/65e54/Captain-Atom.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-iv-hablemos-un-poco-de-js-iii","prev":"react-superhero-v-mobx","next":"react-superhero-iv","tag":"nodejs","limit":3,"skip":0,"primaryTagCount":13,"collectionPaths":{}}},
    "staticQueryHashes": ["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}