{
    "componentChunkName": "component---node-modules-gatsby-theme-try-ghost-src-templates-post-js",
    "path": "/node-js-iii-hablemos-un-poco-de-js-ii/",
    "result": {"data":{"ghostPost":{"id":"Ghost__Post__5a338158333e0f134c248f21","title":"Don't stop the party: Node JS(III) Hablemos un poco de JS (II)","slug":"node-js-iii-hablemos-un-poco-de-js-ii","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/nodebaner.jpg","excerpt":"Closures\nUn closure es una función que devuelve otra función, teniendo la segunda acceso\na los datos de la primera, es decir comparten contexto.\nVeamos un ejemplo sencillo\n\nfunction heroName(surname){\n  return function(name){\n    console.log(name + ' ' + surname);\n  }\n}\nvar dr_Manhattan = heroName('Osterman');\n\nconsole.log(dr_Manhattan('Jon'));\n\n\nComo veis el concepto es bastante sencillo, lo primero instanciamos heroName con\nsu parámetro surname como Osterman, eso lo que hace es asignar la func","custom_excerpt":null,"visibility":"public","created_at_pretty":"11 Aug 2017","published_at_pretty":"4 Sep 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-08-11T08:44:03.000+02:00","published_at":"2017-09-04T10:06:00.000+02:00","updated_at":"2018-01-22T09:55:21.000+01:00","meta_title":null,"meta_description":"Hablaremos de las Closures o clausuras en JavaScript y de lo que se conoce como herencia prototípica","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":"Closures\nUn closure es una función que devuelve otra función, teniendo la segunda acceso\na los datos de la primera, es decir comparten contexto.\nVeamos un ejemplo sencillo\n\nfunction heroName(surname){\n  return function(name){\n    console.log(name + ' ' + surname);\n  }\n}\nvar dr_Manhattan = heroName('Osterman');\n\nconsole.log(dr_Manhattan('Jon'));\n\n\nComo veis el concepto es bastante sencillo, lo primero instanciamos heroName con\nsu parámetro surname como Osterman, eso lo que hace es asignar la función que\nretorna a la variable dr_Manhattan, por lo que ahora mismo dr_Manhattan se ha\nconvertido en un método que espera recibir un nombre por parámetro y que en su\ncontexto tiene acceso al parámetro surname.\nTambien podemos devolver varias funciones no solo una, vamos a cambiar un poco\nnuestra función de retorno:\n\nfunction heroName(surname){\n  return {   \n    getHeroData: function(name){\n        console.log(name + ' ' + surname);\n    },\n    setHeroNewName: function(newName){\n        name = newName;\n    },\n    setHewNewSurname: function(newSurname){\n        surname = newSurname;\n    }\n }\n}\n\n\nAhora ya no podemos usarla igual que antes, estamos devolviendo objetos, por lo\nque tenemos que llamarlos. Lo primero vamos a usar la que seria homónima a la de\nantes, se decir después de la nueva función ponemos\n\nvar dr_Manhattan = heroName('Osterman');\ndr_Manhattan.setHeroNewName('Jon');\ndr_Manhattan.getHeroData();\n\n\nEsta nos devuelve lo mismo de antes. Como vemos ahora la variable dr_Manhattan \nfunciona como una clase con varios métodos(en este caso lo hemos planteado como\nmétodos GETTER y SETTER). Ahora vamos a ver que pasa si usamos el resto,\nañadimos a continuación:\n\ndr_Manhattan.setHeroNewName('Doctor');\ndr_Manhattan.setHewNewSurname('Manhattan');\ndr_Manhattan.getHeroData();\n\n\nCon obtendríamos estos resultados:\n\nComo vemos hemos creado una especie de constructor Héroes de una manera\nrelativamente sencilla.\n\nPrototypes\nBien lo siguiente que veremos serán los prototypes. ¿Que es un prototype? Un\nprototype es una propiedad que tienen todos los objetos de JavaScript(y como\ncasi todo es considerado un objeto son muchas cosas jejejej) y que comparten los\nque son del mismo del mismo tipo aunque ya hayan sido creados. Dentro de un\nprototype podemos tener casi de todo. Veamos un ejemplo:\n\n//Tenemos un constructor en este caso de clones\n//del Dr.Manhattan\nfunction dr_Manhattan_Clone(cloneNumber){\n    this.cloneName = 'clon' + cloneNumber;\n}\n\n\nPara que veamos que este constructor (que es un objeto) ya tiene la propiedad \nprototype hagamos un console.log para ver que tiene\n\nconsole.log(dr_Manhattan_Clone.prototype)\n\n\nEsto nos mostrará\n\nNo tiene nada pero hemos comprobado que por lo menos no da error, es decir, que \nes una propiedad válida de nuestro objeto\nAhora creemos un par de clones y mostremos su nombre o número de clon\n\nvar cloneOne = new dr_Manhattan_Clone(1);\nvar cloneTwo = new dr_Manhattan_Clone(2);\n\nconsole.log(cloneOne.cloneName);\nconsole.log(cloneTwo.cloneName);\n\n\nTodo normal\n\nPor cierto antes de seguir en este caso iremos acumulando código e iremos viendo\ntodo el log desde el principio.\nBueno en la última imagen hemos visto que teniamos el nombre de nuestros clones\ncomo era de esperar. Veamos ahora que tienen nuestros clones\n\nconsole.log(cloneOne);\nconsole.log(cloneTwo);\n\n\n\nBien como vemos son objetos de tipo dr_Manhattan_Clone que tienen una propiedad \ncloneName con su nombre o número.\nTodo normal hasta aquí no?\nAhora creemos nuestro primer prototipo, decimos que clon tiene conocimiento\nsobre la materia y cual no(haremos uno un poco menos listo :P )\n\ndr_Manhattan_Clone.prototype.matterCrontol = function(matter){\n    this.matterKnowledge = matter;\n}\n\n\nHe creado un prototipo llamado matterCrontol que básicamente espera que le\ndigamos si el clon tiene conocimiento de la materia o no. Vamos a ver que tiene\nahora la propiedad prototype de nuestro constructor\n\nconsole.log(dr_Manhattan_Clone.prototype)\n\n\n\nVaya si nos fijamos en la primera y la última línea vemos como ahora sí tenemos\nalgo dentro de la propiedad prototype de nuestro constructor.\nBien pues si la teoría es correcta nuestros clones ya creados deberían poder\nusar esta propiedad, pues comprobemoslo\n\ncloneOne.matterCrontol(true);\ncloneTwo.matterCrontol(false);\n\nconsole.log(cloneOne);\nconsole.log(cloneTwo);\n\n\nSi ejecutamos vemos como no se queja, si no que ademas ahora nuestros clones\ntienen otra propiedad más que ha sido asignada al ejecutar el método \nmatterControl en cada clon.\nComo tal podríamos seguir asignando prototypes a nuestro constructor y lo\ntendríamos disponible en todas nuestras instancias de clones. Todo esto se\nparece un poco a la herencia de otros lenguajes no??\n\nBueno puede que a lo mejor no le veáis muchísima utilidad, pero y si os digo que \npodemos asignar prototypes a objetos propios de JavaScript como al objeto Array\npor ejemplo??\nMiremos primero el objeto Array\n[https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array]\n, si nos fijamos en la parte izquierda podemos ver que realmente todos los\nmétodos que usamos en los objetos ¡¡son prototypes!!, por lo que solo tendríamos\nque añadir otro prototype al objeto array para que lo tengan todos.\n\nArray.prototype.sum = function(){\n    return this.map(function(x){\n        return x + 5;\n    })  \n}\n\n\nBien he creado un protoype sum, que recorre todos los números de un array y le\nsuma 5.\nSi la teoría es cierta, ahora cualquier array que creemos podrá usar esa\npropiedad\n\nvar numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n\n\nY si ejecutamos vemos como si que funciona\n\nProbemos con otro array\n\nvar numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n\nvar numbers2 = [5,10,15,20,25];\nconsole.log(numbers2.sum());\n\n\nY el resultado es\n\nPues como veis ahora podemos usar ese método en todos nuestros arrays, por lo\nque realmente puede llegar a ser muy útil para ciertos entornos donde\nnecesitamos que muchos objetos de repente tengan que hacer algo que antes no\nhacian, incluso nos puede servir para generalizar métodos y que varios objetos\npuedan usar el mismo método (pero esto lo dejaremos para otra ocasión)\nYa va quedando poco para empezar a trabajar con Node no os preocupéis.\nNos vemooossssssss.","html":"<!--kg-card-begin: markdown--><h2 id=\"closures\">Closures</h2>\n<p>Un <strong>closure</strong> es una función que devuelve otra función, teniendo la segunda acceso a los datos de la primera, es decir comparten contexto.<br>\nVeamos un ejemplo sencillo</p>\n<pre><code>function heroName(surname){\n  return function(name){\n    console.log(name + ' ' + surname);\n  }\n}\nvar dr_Manhattan = heroName('Osterman');\n\nconsole.log(dr_Manhattan('Jon'));\n</code></pre>\n<p>Como veis el concepto es bastante sencillo, lo primero instanciamos <strong>heroName</strong> con su parámetro <strong>surname</strong> como <em>Osterman</em>, eso lo que hace es asignar la función que retorna a la variable <strong>dr_Manhattan</strong>, por lo que ahora mismo <strong>dr_Manhattan</strong> se ha convertido en un método que espera recibir un nombre por parámetro y que en su contexto tiene acceso al parámetro <strong>surname</strong>.<br>\nTambien podemos devolver varias funciones no solo una, vamos a cambiar un poco nuestra función de retorno:</p>\n<pre><code>function heroName(surname){\n  return {   \n    getHeroData: function(name){\n        console.log(name + ' ' + surname);\n    },\n    setHeroNewName: function(newName){\n        name = newName;\n    },\n    setHewNewSurname: function(newSurname){\n        surname = newSurname;\n    }\n }\n}\n</code></pre>\n<p>Ahora ya no podemos usarla igual que antes, estamos devolviendo objetos, por lo que tenemos que llamarlos. Lo primero vamos a usar la que seria homónima a la de antes, se decir después de la nueva función ponemos</p>\n<pre><code>var dr_Manhattan = heroName('Osterman');\ndr_Manhattan.setHeroNewName('Jon');\ndr_Manhattan.getHeroData();\n</code></pre>\n<p>Esta nos devuelve lo mismo de antes. Como vemos ahora la variable <strong>dr_Manhattan</strong> funciona como una clase con varios métodos(en este caso lo hemos planteado como métodos GETTER y SETTER). Ahora vamos a ver que pasa si usamos el resto, añadimos a continuación:</p>\n<pre><code>dr_Manhattan.setHeroNewName('Doctor');\ndr_Manhattan.setHewNewSurname('Manhattan');\ndr_Manhattan.getHeroData();\n</code></pre>\n<p>Con obtendríamos estos resultados:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-12.35.09.png\" alt=\"Setter Closures\"><br>\nComo vemos hemos creado una especie de constructor <em>Héroes</em> de una manera relativamente sencilla.</p>\n<h2 id=\"prototypes\">Prototypes</h2>\n<p>Bien lo siguiente que veremos serán los prototypes. ¿Que es un <strong>prototype</strong>? Un prototype es una propiedad que tienen todos los objetos de JavaScript(y como casi todo es considerado un objeto son muchas cosas jejejej) y que comparten los que son del mismo del mismo tipo aunque ya hayan sido creados. Dentro de un prototype podemos tener casi de todo. Veamos un ejemplo:</p>\n<pre><code>//Tenemos un constructor en este caso de clones\n//del Dr.Manhattan\nfunction dr_Manhattan_Clone(cloneNumber){\n    this.cloneName = 'clon' + cloneNumber;\n}\n</code></pre>\n<p>Para que veamos que este constructor (que es un objeto) ya tiene la propiedad <strong>prototype</strong> hagamos un console.log para ver que tiene</p>\n<pre><code>console.log(dr_Manhattan_Clone.prototype)\n</code></pre>\n<p>Esto nos mostrará<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.49.27.png\" alt=\"Prototype empty\"><br>\nNo tiene nada pero hemos comprobado que por lo menos no da error, es decir, que <strong>es una propiedad válida de nuestro objeto</strong><br>\nAhora creemos un par de clones y mostremos su nombre o número de clon</p>\n<pre><code>var cloneOne = new dr_Manhattan_Clone(1);\nvar cloneTwo = new dr_Manhattan_Clone(2);\n\nconsole.log(cloneOne.cloneName);\nconsole.log(cloneTwo.cloneName);\n</code></pre>\n<p>Todo normal<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.52.38.png\" alt=\"Clone names example\"><br>\nPor cierto antes de seguir en este caso iremos acumulando código e iremos viendo todo el log desde el principio.<br>\nBueno en la última imagen hemos visto que teniamos el nombre de nuestros clones como era de esperar. Veamos ahora que tienen nuestros clones</p>\n<pre><code>console.log(cloneOne);\nconsole.log(cloneTwo);\n</code></pre>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.54.38.png\" alt=\"Clone example\"><br>\nBien como vemos son objetos de tipo <em>dr_Manhattan_Clone</em> que tienen una propiedad <em>cloneName</em> con su nombre o número.<br>\nTodo normal hasta aquí no?<br>\nAhora creemos nuestro primer prototipo, decimos que clon tiene conocimiento sobre la materia y cual no(haremos uno un poco menos listo :P )</p>\n<pre><code>dr_Manhattan_Clone.prototype.matterCrontol = function(matter){\n    this.matterKnowledge = matter;\n}\n</code></pre>\n<p>He creado un prototipo llamado <strong>matterCrontol</strong> que básicamente espera que le digamos si el clon tiene conocimiento de la materia o no. Vamos a ver que tiene ahora la propiedad prototype de nuestro constructor</p>\n<pre><code>console.log(dr_Manhattan_Clone.prototype)\n</code></pre>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.08.44.png\" alt=\"First Prototype\"><br>\nVaya si nos fijamos en la primera y la última línea vemos como ahora sí tenemos algo dentro de la propiedad <strong>prototype</strong> de nuestro constructor.<br>\nBien pues si la teoría es correcta nuestros clones ya creados deberían poder usar esta propiedad, pues comprobemoslo</p>\n<pre><code>cloneOne.matterCrontol(true);\ncloneTwo.matterCrontol(false);\n\nconsole.log(cloneOne);\nconsole.log(cloneTwo);\n</code></pre>\n<p>Si ejecutamos vemos como no se queja, si no que ademas ahora nuestros clones tienen otra propiedad más que ha sido asignada al ejecutar el método <strong>matterControl</strong> en cada clon.<br>\nComo tal podríamos seguir asignando prototypes a nuestro constructor y lo tendríamos disponible en todas nuestras instancias de clones. Todo esto se parece un poco a la <strong>herencia</strong> de otros lenguajes no??</p>\n<p>Bueno puede que a lo mejor no le veáis muchísima utilidad, pero y si os digo que <strong>podemos asignar prototypes a objetos propios de JavaScript como al objeto Array por ejemplo??</strong><br>\nMiremos primero el objeto <a href=\"https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array\"><strong>Array</strong></a>, si nos fijamos en la parte izquierda podemos ver que realmente todos los métodos que usamos en los objetos <strong>¡¡son prototypes!!</strong>, por lo que solo tendríamos que añadir otro <strong>prototype</strong> al objeto array para que lo tengan todos.</p>\n<pre><code>Array.prototype.sum = function(){\n    return this.map(function(x){\n        return x + 5;\n    })  \n}\n</code></pre>\n<p>Bien he creado un protoype <strong>sum</strong>, que recorre todos los números de un array y le suma 5.<br>\nSi la teoría es cierta, ahora cualquier array que creemos podrá usar esa propiedad</p>\n<pre><code>var numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n</code></pre>\n<p>Y si ejecutamos vemos como si que funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.36.31.png\" alt=\"Array Prototype example1\"><br>\nProbemos con otro array</p>\n<pre><code>var numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n\nvar numbers2 = [5,10,15,20,25];\nconsole.log(numbers2.sum());\n</code></pre>\n<p>Y el resultado es<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.38.15.png\" alt=\"Array prototype example2\"><br>\nPues como veis ahora podemos usar ese método en todos nuestros arrays, por lo que realmente puede llegar a ser muy útil para ciertos entornos donde necesitamos que muchos objetos de repente tengan que hacer algo que antes no hacian, incluso <strong>nos puede servir para generalizar métodos y que varios objetos puedan usar el mismo método</strong> (pero esto lo dejaremos para otra ocasión)<br>\nYa va quedando poco para empezar a trabajar con Node no os preocupéis.<br>\nNos vemooossssssss.</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/node-js-iii-hablemos-un-poco-de-js-ii/","canonical_url":null,"uuid":"e4e9dc3f-3dc2-48fb-870c-3d9d8e858446","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"46","reading_time":5,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><h2 id=\"closures\">Closures</h2>\n<p>Un <strong>closure</strong> es una función que devuelve otra función, teniendo la segunda acceso a los datos de la primera, es decir comparten contexto.<br>\nVeamos un ejemplo sencillo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function heroName(surname){\n  return function(name){\n    console.log(name + ' ' + surname);\n  }\n}\nvar dr_Manhattan = heroName('Osterman');\n\nconsole.log(dr_Manhattan('Jon'));\n</code></pre></div>\n<p>Como veis el concepto es bastante sencillo, lo primero instanciamos <strong>heroName</strong> con su parámetro <strong>surname</strong> como <em>Osterman</em>, eso lo que hace es asignar la función que retorna a la variable <strong>dr_Manhattan</strong>, por lo que ahora mismo <strong>dr_Manhattan</strong> se ha convertido en un método que espera recibir un nombre por parámetro y que en su contexto tiene acceso al parámetro <strong>surname</strong>.<br>\nTambien podemos devolver varias funciones no solo una, vamos a cambiar un poco nuestra función de retorno:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">function heroName(surname){\n  return {   \n    getHeroData: function(name){\n        console.log(name + ' ' + surname);\n    },\n    setHeroNewName: function(newName){\n        name = newName;\n    },\n    setHewNewSurname: function(newSurname){\n        surname = newSurname;\n    }\n }\n}\n</code></pre></div>\n<p>Ahora ya no podemos usarla igual que antes, estamos devolviendo objetos, por lo que tenemos que llamarlos. Lo primero vamos a usar la que seria homónima a la de antes, se decir después de la nueva función ponemos</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var dr_Manhattan = heroName('Osterman');\ndr_Manhattan.setHeroNewName('Jon');\ndr_Manhattan.getHeroData();\n</code></pre></div>\n<p>Esta nos devuelve lo mismo de antes. Como vemos ahora la variable <strong>dr_Manhattan</strong> funciona como una clase con varios métodos(en este caso lo hemos planteado como métodos GETTER y SETTER). Ahora vamos a ver que pasa si usamos el resto, añadimos a continuación:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">dr_Manhattan.setHeroNewName('Doctor');\ndr_Manhattan.setHewNewSurname('Manhattan');\ndr_Manhattan.getHeroData();\n</code></pre></div>\n<p>Con obtendríamos estos resultados:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-12.35.09.png\" alt=\"Setter Closures\"><br>\nComo vemos hemos creado una especie de constructor <em>Héroes</em> de una manera relativamente sencilla.</p>\n<h2 id=\"prototypes\">Prototypes</h2>\n<p>Bien lo siguiente que veremos serán los prototypes. ¿Que es un <strong>prototype</strong>? Un prototype es una propiedad que tienen todos los objetos de JavaScript(y como casi todo es considerado un objeto son muchas cosas jejejej) y que comparten los que son del mismo del mismo tipo aunque ya hayan sido creados. Dentro de un prototype podemos tener casi de todo. Veamos un ejemplo:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">//Tenemos un constructor en este caso de clones\n//del Dr.Manhattan\nfunction dr_Manhattan_Clone(cloneNumber){\n    this.cloneName = 'clon' + cloneNumber;\n}\n</code></pre></div>\n<p>Para que veamos que este constructor (que es un objeto) ya tiene la propiedad <strong>prototype</strong> hagamos un console.log para ver que tiene</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">console.log(dr_Manhattan_Clone.prototype)\n</code></pre></div>\n<p>Esto nos mostrará<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.49.27.png\" alt=\"Prototype empty\"><br>\nNo tiene nada pero hemos comprobado que por lo menos no da error, es decir, que <strong>es una propiedad válida de nuestro objeto</strong><br>\nAhora creemos un par de clones y mostremos su nombre o número de clon</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var cloneOne = new dr_Manhattan_Clone(1);\nvar cloneTwo = new dr_Manhattan_Clone(2);\n\nconsole.log(cloneOne.cloneName);\nconsole.log(cloneTwo.cloneName);\n</code></pre></div>\n<p>Todo normal<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.52.38.png\" alt=\"Clone names example\"><br>\nPor cierto antes de seguir en este caso iremos acumulando código e iremos viendo todo el log desde el principio.<br>\nBueno en la última imagen hemos visto que teniamos el nombre de nuestros clones como era de esperar. Veamos ahora que tienen nuestros clones</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">console.log(cloneOne);\nconsole.log(cloneTwo);\n</code></pre></div>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.54.38.png\" alt=\"Clone example\"><br>\nBien como vemos son objetos de tipo <em>dr_Manhattan_Clone</em> que tienen una propiedad <em>cloneName</em> con su nombre o número.<br>\nTodo normal hasta aquí no?<br>\nAhora creemos nuestro primer prototipo, decimos que clon tiene conocimiento sobre la materia y cual no(haremos uno un poco menos listo :P )</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">dr_Manhattan_Clone.prototype.matterCrontol = function(matter){\n    this.matterKnowledge = matter;\n}\n</code></pre></div>\n<p>He creado un prototipo llamado <strong>matterCrontol</strong> que básicamente espera que le digamos si el clon tiene conocimiento de la materia o no. Vamos a ver que tiene ahora la propiedad prototype de nuestro constructor</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">console.log(dr_Manhattan_Clone.prototype)\n</code></pre></div>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.08.44.png\" alt=\"First Prototype\"><br>\nVaya si nos fijamos en la primera y la última línea vemos como ahora sí tenemos algo dentro de la propiedad <strong>prototype</strong> de nuestro constructor.<br>\nBien pues si la teoría es correcta nuestros clones ya creados deberían poder usar esta propiedad, pues comprobemoslo</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">cloneOne.matterCrontol(true);\ncloneTwo.matterCrontol(false);\n\nconsole.log(cloneOne);\nconsole.log(cloneTwo);\n</code></pre></div>\n<p>Si ejecutamos vemos como no se queja, si no que ademas ahora nuestros clones tienen otra propiedad más que ha sido asignada al ejecutar el método <strong>matterControl</strong> en cada clon.<br>\nComo tal podríamos seguir asignando prototypes a nuestro constructor y lo tendríamos disponible en todas nuestras instancias de clones. Todo esto se parece un poco a la <strong>herencia</strong> de otros lenguajes no??</p>\n<p>Bueno puede que a lo mejor no le veáis muchísima utilidad, pero y si os digo que <strong>podemos asignar prototypes a objetos propios de JavaScript como al objeto Array por ejemplo??</strong><br>\nMiremos primero el objeto <a href=\"https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array\"><strong>Array</strong></a>, si nos fijamos en la parte izquierda podemos ver que realmente todos los métodos que usamos en los objetos <strong>¡¡son prototypes!!</strong>, por lo que solo tendríamos que añadir otro <strong>prototype</strong> al objeto array para que lo tengan todos.</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Array.prototype.sum = function(){\n    return this.map(function(x){\n        return x + 5;\n    })  \n}\n</code></pre></div>\n<p>Bien he creado un protoype <strong>sum</strong>, que recorre todos los números de un array y le suma 5.<br>\nSi la teoría es cierta, ahora cualquier array que creemos podrá usar esa propiedad</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n</code></pre></div>\n<p>Y si ejecutamos vemos como si que funciona<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.36.31.png\" alt=\"Array Prototype example1\"><br>\nProbemos con otro array</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">var numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n\nvar numbers2 = [5,10,15,20,25];\nconsole.log(numbers2.sum());\n</code></pre></div>\n<p>Y el resultado es<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.38.15.png\" alt=\"Array prototype example2\"><br>\nPues como veis ahora podemos usar ese método en todos nuestros arrays, por lo que realmente puede llegar a ser muy útil para ciertos entornos donde necesitamos que muchos objetos de repente tengan que hacer algo que antes no hacian, incluso <strong>nos puede servir para generalizar métodos y que varios objetos puedan usar el mismo método</strong> (pero esto lo dejaremos para otra ocasión)<br>\nYa va quedando poco para empezar a trabajar con Node no os preocupéis.<br>\nNos vemooossssssss.</p>\n<!--kg-card-end: markdown-->","htmlAst":{"type":"root","children":[{"type":"comment","value":"kg-card-begin: markdown"},{"type":"element","tagName":"h2","properties":{"id":"closures"},"children":[{"type":"text","value":"Closures"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"closure"}]},{"type":"text","value":" es una función que devuelve otra función, teniendo la segunda acceso a los datos de la primera, es decir comparten contexto."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVeamos un ejemplo 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":"function heroName(surname){\n  return function(name){\n    console.log(name + ' ' + surname);\n  }\n}\nvar dr_Manhattan = heroName('Osterman');\n\nconsole.log(dr_Manhattan('Jon'));\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Como veis el concepto es bastante sencillo, lo primero instanciamos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"heroName"}]},{"type":"text","value":" con su parámetro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"surname"}]},{"type":"text","value":" como "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Osterman"}]},{"type":"text","value":", eso lo que hace es asignar la función que retorna a la variable "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"dr_Manhattan"}]},{"type":"text","value":", por lo que ahora mismo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"dr_Manhattan"}]},{"type":"text","value":" se ha convertido en un método que espera recibir un nombre por parámetro y que en su contexto tiene acceso al parámetro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"surname"}]},{"type":"text","value":"."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTambien podemos devolver varias funciones no solo una, vamos a cambiar un poco nuestra función de retorno:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"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 heroName(surname){\n  return {   \n    getHeroData: function(name){\n        console.log(name + ' ' + surname);\n    },\n    setHeroNewName: function(newName){\n        name = newName;\n    },\n    setHewNewSurname: function(newSurname){\n        surname = newSurname;\n    }\n }\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Ahora ya no podemos usarla igual que antes, estamos devolviendo objetos, por lo que tenemos que llamarlos. Lo primero vamos a usar la que seria homónima a la de antes, se decir después de la nueva función 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":"var dr_Manhattan = heroName('Osterman');\ndr_Manhattan.setHeroNewName('Jon');\ndr_Manhattan.getHeroData();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esta nos devuelve lo mismo de antes. Como vemos ahora la variable "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"dr_Manhattan"}]},{"type":"text","value":" funciona como una clase con varios métodos(en este caso lo hemos planteado como métodos GETTER y SETTER). Ahora vamos a ver que pasa si usamos el resto, añadimos a continuació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":"dr_Manhattan.setHeroNewName('Doctor');\ndr_Manhattan.setHewNewSurname('Manhattan');\ndr_Manhattan.getHeroData();\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con obtendríamos estos resultados:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-12.35.09.png","alt":"Setter Closures"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo vemos hemos creado una especie de constructor "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Héroes"}]},{"type":"text","value":" de una manera relativamente sencilla."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{"id":"prototypes"},"children":[{"type":"text","value":"Prototypes"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien lo siguiente que veremos serán los prototypes. ¿Que es un "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"prototype"}]},{"type":"text","value":"? Un prototype es una propiedad que tienen todos los objetos de JavaScript(y como casi todo es considerado un objeto son muchas cosas jejejej) y que comparten los que son del mismo del mismo tipo aunque ya hayan sido creados. Dentro de un prototype podemos tener casi de todo. Veamos un 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":"//Tenemos un constructor en este caso de clones\n//del Dr.Manhattan\nfunction dr_Manhattan_Clone(cloneNumber){\n    this.cloneName = 'clon' + cloneNumber;\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Para que veamos que este constructor (que es un objeto) ya tiene la propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"prototype"}]},{"type":"text","value":" hagamos un console.log para ver que tiene"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"console.log(dr_Manhattan_Clone.prototype)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Esto nos mostrará"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.49.27.png","alt":"Prototype empty"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nNo tiene nada pero hemos comprobado que por lo menos no da error, es decir, que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"es una propiedad válida de nuestro objeto"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora creemos un par de clones y mostremos su nombre o número de clon"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"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 cloneOne = new dr_Manhattan_Clone(1);\nvar cloneTwo = new dr_Manhattan_Clone(2);\n\nconsole.log(cloneOne.cloneName);\nconsole.log(cloneTwo.cloneName);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Todo normal"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.52.38.png","alt":"Clone names example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor cierto antes de seguir en este caso iremos acumulando código e iremos viendo todo el log desde el principio."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBueno en la última imagen hemos visto que teniamos el nombre de nuestros clones como era de esperar. Veamos ahora que tienen nuestros clones"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"console.log(cloneOne);\nconsole.log(cloneTwo);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.54.38.png","alt":"Clone example"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBien como vemos son objetos de tipo "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"dr_Manhattan_Clone"}]},{"type":"text","value":" que tienen una propiedad "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"cloneName"}]},{"type":"text","value":" con su nombre o número."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nTodo normal hasta aquí no?"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nAhora creemos nuestro primer prototipo, decimos que clon tiene conocimiento sobre la materia y cual no(haremos uno un poco menos listo :P )"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"dr_Manhattan_Clone.prototype.matterCrontol = function(matter){\n    this.matterKnowledge = matter;\n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"He creado un prototipo llamado "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"matterCrontol"}]},{"type":"text","value":" que básicamente espera que le digamos si el clon tiene conocimiento de la materia o no. Vamos a ver que tiene ahora la propiedad prototype de nuestro constructor"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"console.log(dr_Manhattan_Clone.prototype)\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.08.44.png","alt":"First Prototype"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nVaya si nos fijamos en la primera y la última línea vemos como ahora sí tenemos algo dentro de la propiedad "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"prototype"}]},{"type":"text","value":" de nuestro constructor."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBien pues si la teoría es correcta nuestros clones ya creados deberían poder usar esta propiedad, pues comprobemoslo"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"cloneOne.matterCrontol(true);\ncloneTwo.matterCrontol(false);\n\nconsole.log(cloneOne);\nconsole.log(cloneTwo);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si ejecutamos vemos como no se queja, si no que ademas ahora nuestros clones tienen otra propiedad más que ha sido asignada al ejecutar el método "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"matterControl"}]},{"type":"text","value":" en cada clon."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nComo tal podríamos seguir asignando prototypes a nuestro constructor y lo tendríamos disponible en todas nuestras instancias de clones. Todo esto se parece un poco a la "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"herencia"}]},{"type":"text","value":" de otros lenguajes no??"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bueno puede que a lo mejor no le veáis muchísima utilidad, pero y si os digo que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"podemos asignar prototypes a objetos propios de JavaScript como al objeto Array por ejemplo??"}]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nMiremos primero el objeto "},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Array"}]}]},{"type":"text","value":", si nos fijamos en la parte izquierda podemos ver que realmente todos los métodos que usamos en los objetos "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"¡¡son prototypes!!"}]},{"type":"text","value":", por lo que solo tendríamos que añadir otro "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"prototype"}]},{"type":"text","value":" al objeto array para que lo tengan todos."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"Array.prototype.sum = function(){\n    return this.map(function(x){\n        return x + 5;\n    })  \n}\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien he creado un protoype "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"sum"}]},{"type":"text","value":", que recorre todos los números de un array y le suma 5."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nSi la teoría es cierta, ahora cualquier array que creemos podrá usar esa propiedad"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"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 numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y si ejecutamos vemos como si 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/08/Screen-Shot-2017-08-12-at-14.36.31.png","alt":"Array Prototype example1"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nProbemos con otro array"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"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 numbers = [1,2,3,4,5];\nvar result = numbers.sum();\nconsole.log(result);\n\nvar numbers2 = [5,10,15,20,25];\nconsole.log(numbers2.sum());\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Y el resultado es"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.38.15.png","alt":"Array prototype example2"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPues como veis ahora podemos usar ese método en todos nuestros arrays, por lo que realmente puede llegar a ser muy útil para ciertos entornos donde necesitamos que muchos objetos de repente tengan que hacer algo que antes no hacian, incluso "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"nos puede servir para generalizar métodos y que varios objetos puedan usar el mismo método"}]},{"type":"text","value":" (pero esto lo dejaremos para otra ocasión)"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nYa va quedando poco para empezar a trabajar con Node no os preocupéis."},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nNos vemooossssssss."}]},{"type":"text","value":"\n"},{"type":"comment","value":"kg-card-end: markdown"}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"closures","heading":"Closures"},{"id":"prototypes","heading":"Prototypes"}]},"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__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"}}}},"next":{"id":"Ghost__Post__5a338158333e0f134c248f1d","title":"React Superhero (III): Entorno de desarrollo","slug":"react-js-iii-entorno-de-desarrollo","featured":false,"feature_image":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Captain-Atom.jpg","excerpt":"Bien antes de ponernos serios desarrollando algo más complejo con React,\nnecesitamos configurar nuestro entorno ya que una app de React necesita de\nvarias dependencias para funcionar correctamente en producción(además que nos\nfacilitan un poco el ir desarrollando).\n\nHasta hace poco, con React debíamos hacer toda la configuración y preparación\ndel entorno a mano, pero nuestros amigos de Facebook, se han creado una especie\nde atajo al estilo AngularCLI(más info Create React APP\n[https://github.com","custom_excerpt":null,"visibility":"public","created_at_pretty":"4 Aug 2017","published_at_pretty":"28 Aug 2017","updated_at_pretty":"22 Jan 2018","created_at":"2017-08-04T08:46:04.000+02:00","published_at":"2017-08-28T10:03:00.000+02:00","updated_at":"2018-01-22T09:56:23.000+01:00","meta_title":null,"meta_description":"Preparando nuestro entorno de desarrollo 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":"Bien antes de ponernos serios desarrollando algo más complejo con React,\nnecesitamos configurar nuestro entorno ya que una app de React necesita de\nvarias dependencias para funcionar correctamente en producción(además que nos\nfacilitan un poco el ir desarrollando).\n\nHasta hace poco, con React debíamos hacer toda la configuración y preparación\ndel entorno a mano, pero nuestros amigos de Facebook, se han creado una especie\nde atajo al estilo AngularCLI(más info Create React APP\n[https://github.com/facebookincubator/create-react-app]), para usarlo lo primero\nes instalar NodeJS [https://nodejs.org/es/], es suficiente con instalar la\nversión LTS desde la página principal, para el que no lo sepa NodeJS es la\nopción servidor de JS, es orientado a eventos lo que le permite manejar un gran\nnúmero de peticiones, por el momento no voy a entrar mucho en esto, tengo\nintención de crear una linea de post solo de Node por lo que si os interesa\nestar atentos ;).\n\nUna vez instalado podemos comprobar que se ha instalado correctamente con las\nsiguientes instrucciones en nuestra consola de comandos preferida:\n\n#Para ver la versión de NodeJS\nnode -v\n#La versión de Node Package Manager\nnpm -v \n\n\n\nYo simplemente he encadenado los comandos pero os debería salir algo similar a\neso.\n\nBien lo primero de todo es hacer que NPM instale los paquetes que necesitamos:\n\nnpm -g install create-react-app\n\n\nEs tan sencillo como indicarlo con el nombre, y el -g es para que nos lo instale\nglobalmente y podamos usarlo en cualquier sitio, si no lo pusieramos solo nos lo\ninstalaría en el directorio donde estuviéramos trabajando en la linea de\ncomandos. Una vez ejecutado se descargará y configurará algunas cosas el solito,\nveréis unas cuantas líneas como estas:\n\nBien una vez instalado ya podemos crear nuestro entorno para la app que vamos a\ndesarrollar, para ello solo necesitamos llamar a nuestro nuevo comando he\nindicarle al nombre de la app que deseamos crear:\n\ncreate-react-app nuclear_superhero_app\n\n\nUna vez terminado el proceso nos saldrá algo similar a esto\n\nPor último para empezar a ver la utilidad de esto tenemos que hacer lo que nos\nsugieren al final, entrar en el directorio y ejecutar start:\n\ncd nuclear_superhero_app\nnpm start\n\n\nSi todo ha ido bien se os habrá abierto otra pestaña en el navegador con esto:\n\n\nBásicamente nos ha levantado un \"servidor\" en local en el puerto 3000 donde\npodremos ir viendo los cambios en nuestra aplicación casi en tiempo real. Si\nqueremos para el servidor es suficiente con irnos a la consola desde donde lo\nhemos lanzado y detener el proceso con ctrl+c o como soláis hacerlo.\n\nCon esto ya tendríamos lo que necesitamos para empezar a trabajar realmente con\nReact, que es lo que haremos desde el próximo post, si alguien ha tenido\nproblemas o quiere saber algo de Node que lo ponga en comentarios y lo vamos\nviendo.Nos vemoooossssss.","html":"<!--kg-card-begin: markdown--><p>Bien antes de ponernos serios desarrollando algo más complejo con React, necesitamos configurar nuestro entorno ya que una app de React necesita de varias dependencias para funcionar correctamente en producción(además que nos facilitan un poco el ir desarrollando).</p>\n<p>Hasta hace poco, con React debíamos hacer toda la configuración y preparación del entorno a mano, pero nuestros amigos de Facebook, se han creado una especie de atajo al estilo <strong>AngularCLI</strong>(más info <a href=\"https://github.com/facebookincubator/create-react-app\">Create React APP</a>), para usarlo lo primero es instalar <a href=\"https://nodejs.org/es/\">NodeJS</a>, es suficiente con instalar la versión <strong>LTS</strong> desde la página principal, para el que no lo sepa NodeJS es la opción servidor de JS, es orientado a eventos lo que le permite manejar un gran número de peticiones, por el momento no voy a entrar mucho en esto, tengo intención de crear una linea de post solo de Node por lo que si os interesa estar atentos ;).</p>\n<p>Una vez instalado podemos comprobar que se ha instalado correctamente con las siguientes instrucciones en nuestra consola de comandos preferida:</p>\n<pre><code>#Para ver la versión de NodeJS\nnode -v\n#La versión de Node Package Manager\nnpm -v \n</code></pre>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-08.54.25.png\" alt=\"Node Check Install\"><br>\nYo simplemente he encadenado los comandos pero os debería salir algo similar a eso.</p>\n<p>Bien lo primero de todo es hacer que <strong>NPM</strong> instale los paquetes que necesitamos:</p>\n<pre><code>npm -g install create-react-app\n</code></pre>\n<p>Es tan sencillo como indicarlo con el nombre, y el <strong>-g</strong> es para que nos lo instale globalmente y podamos usarlo en cualquier sitio, si no lo pusieramos solo nos lo instalaría en el directorio donde estuviéramos trabajando en la linea de comandos. Una vez ejecutado se descargará y configurará algunas cosas el solito, veréis unas cuantas líneas como estas:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.03.41.png\" alt=\"Npm list install React\"><br>\nBien una vez instalado ya podemos crear nuestro entorno para la app que vamos a desarrollar, para ello solo necesitamos llamar a nuestro nuevo comando he indicarle al nombre de la app que deseamos crear:</p>\n<pre><code>create-react-app nuclear_superhero_app\n</code></pre>\n<p>Una vez terminado el proceso nos saldrá algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.08.17.png\" alt=\"Create-react-app command\"><br>\nPor último para empezar a ver la utilidad de esto tenemos que hacer lo que nos sugieren al final, entrar en el directorio y ejecutar <strong>start</strong>:</p>\n<pre><code>cd nuclear_superhero_app\nnpm start\n</code></pre>\n<p>Si todo ha ido bien se os habrá abierto otra pestaña en el navegador con esto:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.11.31.png\" alt=\"React Start\"></p>\n<p>Básicamente nos ha levantado un &quot;servidor&quot; en local en el puerto 3000 donde podremos ir viendo los cambios en nuestra aplicación casi en tiempo real. Si queremos para el servidor es suficiente con irnos a la consola desde donde lo hemos lanzado y detener el proceso con <strong>ctrl+c</strong> o como soláis hacerlo.</p>\n<p>Con esto ya tendríamos lo que necesitamos para empezar a trabajar realmente con React, que es lo que haremos desde el próximo post, si alguien ha tenido problemas o quiere saber algo de Node que lo ponga en comentarios y lo vamos viendo.Nos vemoooossssss.</p>\n<!--kg-card-end: markdown-->","url":"https://jlgarcia.fulldev.ninja/react-js-iii-entorno-de-desarrollo/","canonical_url":null,"uuid":"84b25ae1-1dbe-4e10-b5de-e9c0dec2d671","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"42","reading_time":3,"send_email_when_published":false,"email_subject":null,"childHtmlRehype":{"html":"<!--kg-card-begin: markdown--><p>Bien antes de ponernos serios desarrollando algo más complejo con React, necesitamos configurar nuestro entorno ya que una app de React necesita de varias dependencias para funcionar correctamente en producción(además que nos facilitan un poco el ir desarrollando).</p>\n<p>Hasta hace poco, con React debíamos hacer toda la configuración y preparación del entorno a mano, pero nuestros amigos de Facebook, se han creado una especie de atajo al estilo <strong>AngularCLI</strong>(más info <a href=\"https://github.com/facebookincubator/create-react-app\">Create React APP</a>), para usarlo lo primero es instalar <a href=\"https://nodejs.org/es/\">NodeJS</a>, es suficiente con instalar la versión <strong>LTS</strong> desde la página principal, para el que no lo sepa NodeJS es la opción servidor de JS, es orientado a eventos lo que le permite manejar un gran número de peticiones, por el momento no voy a entrar mucho en esto, tengo intención de crear una linea de post solo de Node por lo que si os interesa estar atentos ;).</p>\n<p>Una vez instalado podemos comprobar que se ha instalado correctamente con las siguientes instrucciones en nuestra consola de comandos preferida:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">#Para ver la versión de NodeJS\nnode -v\n#La versión de Node Package Manager\nnpm -v \n</code></pre></div>\n<p><img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-08.54.25.png\" alt=\"Node Check Install\"><br>\nYo simplemente he encadenado los comandos pero os debería salir algo similar a eso.</p>\n<p>Bien lo primero de todo es hacer que <strong>NPM</strong> instale los paquetes que necesitamos:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm -g install create-react-app\n</code></pre></div>\n<p>Es tan sencillo como indicarlo con el nombre, y el <strong>-g</strong> es para que nos lo instale globalmente y podamos usarlo en cualquier sitio, si no lo pusieramos solo nos lo instalaría en el directorio donde estuviéramos trabajando en la linea de comandos. Una vez ejecutado se descargará y configurará algunas cosas el solito, veréis unas cuantas líneas como estas:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.03.41.png\" alt=\"Npm list install React\"><br>\nBien una vez instalado ya podemos crear nuestro entorno para la app que vamos a desarrollar, para ello solo necesitamos llamar a nuestro nuevo comando he indicarle al nombre de la app que deseamos crear:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">create-react-app nuclear_superhero_app\n</code></pre></div>\n<p>Una vez terminado el proceso nos saldrá algo similar a esto<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.08.17.png\" alt=\"Create-react-app command\"><br>\nPor último para empezar a ver la utilidad de esto tenemos que hacer lo que nos sugieren al final, entrar en el directorio y ejecutar <strong>start</strong>:</p>\n<div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">cd nuclear_superhero_app\nnpm start\n</code></pre></div>\n<p>Si todo ha ido bien se os habrá abierto otra pestaña en el navegador con esto:<br>\n<img src=\"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.11.31.png\" alt=\"React Start\"></p>\n<p>Básicamente nos ha levantado un \"servidor\" en local en el puerto 3000 donde podremos ir viendo los cambios en nuestra aplicación casi en tiempo real. Si queremos para el servidor es suficiente con irnos a la consola desde donde lo hemos lanzado y detener el proceso con <strong>ctrl+c</strong> o como soláis hacerlo.</p>\n<p>Con esto ya tendríamos lo que necesitamos para empezar a trabajar realmente con React, que es lo que haremos desde el próximo post, si alguien ha tenido problemas o quiere saber algo de Node que lo ponga en comentarios y lo vamos viendo.Nos vemoooossssss.</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 antes de ponernos serios desarrollando algo más complejo con React, necesitamos configurar nuestro entorno ya que una app de React necesita de varias dependencias para funcionar correctamente en producción(además que nos facilitan un poco el ir desarrollando)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Hasta hace poco, con React debíamos hacer toda la configuración y preparación del entorno a mano, pero nuestros amigos de Facebook, se han creado una especie de atajo al estilo "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"AngularCLI"}]},{"type":"text","value":"(más info "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/facebookincubator/create-react-app"},"children":[{"type":"text","value":"Create React APP"}]},{"type":"text","value":"), para usarlo lo primero es instalar "},{"type":"element","tagName":"a","properties":{"href":"https://nodejs.org/es/"},"children":[{"type":"text","value":"NodeJS"}]},{"type":"text","value":", es suficiente con instalar la versión "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"LTS"}]},{"type":"text","value":" desde la página principal, para el que no lo sepa NodeJS es la opción servidor de JS, es orientado a eventos lo que le permite manejar un gran número de peticiones, por el momento no voy a entrar mucho en esto, tengo intención de crear una linea de post solo de Node por lo que si os interesa estar atentos ;)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Una vez instalado podemos comprobar que se ha instalado correctamente con las siguientes instrucciones en nuestra consola de comandos preferida:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"#Para ver la versión de NodeJS\nnode -v\n#La versión de Node Package Manager\nnpm -v \n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-08.54.25.png","alt":"Node Check Install"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nYo simplemente he encadenado los comandos pero os debería salir algo similar a eso."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Bien lo primero de todo es hacer que "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"NPM"}]},{"type":"text","value":" instale los paquetes que necesitamos:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"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 -g install create-react-app\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Es tan sencillo como indicarlo con el nombre, y el "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"-g"}]},{"type":"text","value":" es para que nos lo instale globalmente y podamos usarlo en cualquier sitio, si no lo pusieramos solo nos lo instalaría en el directorio donde estuviéramos trabajando en la linea de comandos. Una vez ejecutado se descargará y configurará algunas cosas el solito, veréis unas cuantas líneas como estas:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.03.41.png","alt":"Npm list install React"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nBien una vez instalado ya podemos crear nuestro entorno para la app que vamos a desarrollar, para ello solo necesitamos llamar a nuestro nuevo comando he indicarle al nombre de la app que deseamos crear:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"create-react-app nuclear_superhero_app\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Una vez terminado el proceso nos saldrá algo similar a esto"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.08.17.png","alt":"Create-react-app command"},"children":[]},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\nPor último para empezar a ver la utilidad de esto tenemos que hacer lo que nos sugieren al final, entrar en el directorio y ejecutar "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"start"}]},{"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":"cd nuclear_superhero_app\nnpm start\n"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Si todo ha ido bien se os habrá abierto otra pestaña en el navegador con esto:"},{"type":"element","tagName":"br","properties":{},"children":[]},{"type":"text","value":"\n"},{"type":"element","tagName":"img","properties":{"src":"https://jlgarcia.fulldev.ninja/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.11.31.png","alt":"React Start"},"children":[]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Básicamente nos ha levantado un \"servidor\" en local en el puerto 3000 donde podremos ir viendo los cambios en nuestra aplicación casi en tiempo real. Si queremos para el servidor es suficiente con irnos a la consola desde donde lo hemos lanzado y detener el proceso con "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"ctrl+c"}]},{"type":"text","value":" o como soláis hacerlo."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Con esto ya tendríamos lo que necesitamos para empezar a trabajar realmente con React, que es lo que haremos desde el próximo post, si alguien ha tenido problemas o quiere saber algo de Node que lo ponga en comentarios y lo vamos viendo.Nos vemoooossssss."}]},{"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":"node-js-iii-hablemos-un-poco-de-js-ii","prev":"react-superhero-iv","next":"react-js-iii-entorno-de-desarrollo","tag":"nodejs","limit":3,"skip":0,"primaryTagCount":13,"collectionPaths":{}}},
    "staticQueryHashes": ["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}