<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Node - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Node - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:37:29 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/tag/node/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo escribir Pruebas usando el Ejecutor de Pruebas de Node.js y mongodb-memory-server ]]>
                </title>
                <description>
                    <![CDATA[ Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-escribir-pruebas-usando-el-ejecutor-de-pruebas-de-node-js-y-mongodb-memory-server/</link>
                <guid isPermaLink="false">67bd1d95f9cd6804c5816fa9</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mongo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pruebas unitarias ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Tue, 15 Apr 2025 14:27:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2025/02/Captura-desde-2025-02-24-22-33-31.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-write-tests-using-the-nodejs-test-runner-and-mongodb-memory-server/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Write Tests Using the Node.js Test Runner and mongodb-memory-server</a>
      </p><p>Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo de ejecución de las pruebas fue reducido cerca de un 66%.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738830673460/1560f7a3-38c1-42f3-8944-df06b40d73e4.png" class="kg-image" alt="76% reduction in time taken to run tests in Jest vs Node.js test runner" width="560" height="478" loading="lazy"></figure><p>Decidí compartirte cómo pude implementarlo. Pienso que te será de utilidad, ya que es más rentable (en términos de reducir dinero gastado en ejecutar pruebas en CI/CD), y también mejora tu experiencia de desarrollo.</p><h2 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h2><ul><li><a href="#pre-requisitos">Pre-requisitos</a></li><li><a href="#ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</a></li><li><a href="#servidor-memoria-mongodb">El Servidor en memoria de MongoDB</a></li></ul><!--kg-card-begin: markdown--><ul>
<li><a href="#como-escribir-pruebas">Cómo escribir las Pruebas</a>
<ol>
<li><a href="#configurar-proyecto">Configurar el Proyecto</a></li>
<li><a href="#configurar-esquema-mongoose">Configurar el Esquema de Mongoose</a></li>
<li><a href="#configurar-servicios">Configurar los Servicios</a></li>
<li><a href="#configurar-pruebas">Configurar las Pruebas</a></li>
<li><a href="#escribir-pruebas">Escribir las Pruebas</a></li>
<li><a href="#pasar-pruebas">Pasar las Pruebas</a></li>
<li><a href="#usa-typescript-opcional">Usar TypeScript (Opcional)</a></li>
</ol>
</li>
</ul>
<!--kg-card-end: markdown--><ul><li><a href="#conclusion">Conclusión</a></li></ul><!--kg-card-begin: html--><h2 id="pre-requisitos">Pre-requisitos</h2><!--kg-card-end: html--><p>Para seguir esta guía, deberías de tener experiencia trabajando con Node.js, MongoDB y Mongoose (o cualquier otro mapeador de datos de objetos de MongoDB). Deberías también tener instalado Node.js (al menos la versión 20.18.2) y MongoDB (Compass la versión GUI) en tu computadora.</p><!--kg-card-begin: html--><h2 id="ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</h2><!--kg-card-end: html--><p>El ejecutor de pruebas de Node.js fue introducido como una característica experimental en la versión 18 de Node.js. Se volvió disponible oficialmente en la versión 20. Te da la habilidad de:</p><ol><li>Ejecutar pruebas</li><li>Reportar resultados de las pruebas</li><li>Reportar cobertura de las pruebas (todavía experimental en la versión 23)</li></ol><p>Es una buena idea el usar el ejecutor de pruebas incorporado cuando se escriban pruebas en Node.js porque significa que tienes que usar menos dependencias externas. No necesitas instalar una librería externa (y sus dependencias entre pares) para ejecutar las pruebas.</p><p>El mejor ejecutor incorporado también es el más rápido. Basado en mi experiencia usándolo en dos proyectos (los cuales usaron Jest), vi mejoras de al menos una reducción del 66% en el tiempo que tomó ejecutar las pruebas completamente.</p><p>Y a diferencia de otros frameworks o librerías de pruebas, el ejecutor de pruebas de Node.js fue construido especialmente para proyectos de Node.js. No trata de acomodar las especificaciones de otros entornos de programación como el navegador. Las especificaciones de Node.js son su principal y única prioridad.</p><!--kg-card-begin: html--><h2 id="servidor-memoria-mongodb">El Servidor en memoria de MongoDB</h2><!--kg-card-end: html--><p>Para las pruebas que involucran el hacer peticiones a una base de datos, algunos desarrolladores prefieren imitar las peticiones para evitar hacer peticiones a una base de datos real. Hacen esto porque hacer una petición a una base de datos real requiere un montón de configuraciones que puede costar tiempo y recursos.</p><p>Escribir y solicitar datos usando una base de datos real es más lento <a href="https://www.mongodb.com/resources/basics/databases/in-memory-database">comparado con escribir y solicitar datos de la memoria</a>. Cuando se ejecutan pruebas automatizadas, usando un servidor de MongoDB real será más lento que usar un servidor de base de datos en memoria, y ahí es donde <a href="https://github.com/typegoose/mongodb-memory-server">mongodb-memory-server</a> se vuelve útil.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738832586702/62360547-70e8-4e74-854f-c7ad74d182ea.png" class="kg-image" alt="Comparison between memory and database communication with CPU" width="631" height="256" loading="lazy"></figure><p>Según su documentación, mongodb-memory-server crea y comienza un servidor de MongoDB real de forma programática desde dentro de Node.js, pero usa una base de datos en memoria por defecto. También te permite conectar el servidor de base de datos que crea usando tu mapeador de datos de objetos preferido tales como Mongoose, Prisma, o TypeORM. En esta guía, usaremos <a href="https://mongoosejs.com/">Mongoose</a> (v.8.9.6).</p><p>Ya que los datos almacenados por mongodb-memory-server reside en la memoria por defecto, es más rápido leer y escribir en él que cuando se usa una base de datos real. mongodb-memory-server también es más fácil de configurar. Estos beneficios lo hace una buena elección para usarlo como un servidor de base de datos para escribir pruebas.</p><p><strong>Nota</strong>: asegúrate de instalar la versión 9.1.6 de mongodb-memory-server para seguir esta guía. La versión 10 actualmente tiene problemas con limpiar los recursos después que se hacen las pruebas. Mira este problema con el título "<a href="https://github.com/typegoose/mongodb-memory-server/issues/912">Node forking will include any <code>--import</code> from the original command</a>".</p><p>El problema ha sido resuelto al tiempo de escribir este artículo, pero el arreglo no ha sido fusionado para las instalaciones.</p><!--kg-card-begin: html--><h2 id="como-escribir-pruebas">Cómo escribir las Pruebas</h2><!--kg-card-end: html--><p>Ahora te guiaré a través de los siguientes pasos para que comiences a escribir las pruebas:</p><ol><li>Configurar el proyecto</li><li>Configurar el esquema de Mongoose</li><li>Configurar los servicios</li><li>Configurar las pruebas</li><li>Escribir las pruebas</li><li>Pasar las pruebas</li><li>Usa TypeScript (Opcional)</li></ol><!--kg-card-begin: html--><h3 id="configurar-proyecto">1. Configurar el Proyecto</h3><!--kg-card-end: html--><p>Creé un repositorio de Github para facilitarte que sigas esta guía. Clona este repositorio en <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a> y dirígete a la rama <code>01-setup</code>. </p><p>En <code>01-setup</code>, las dependencias para el proyecto están el archivo <code>package.json</code>. Instala las dependencias usando el comando <code>npm install</code> para configurar el proyecto. Asegúrate de que la configuración esté completa y correcta, ejecuta el comando <code>node .</code> en la terminal de tu proyecto. Deberías ver tu versión de Node.js &nbsp;como una salida en la terminal.</p><pre><code class="language-bash"># instala las dependencias
npm install
...
# ejecuta el comando node
node .
# la salida
You are running Node.js v22.13.1
</code></pre><!--kg-card-begin: html--><h3 id="configurar-esquema-mongoose">2. Configurar el Esquema de Mongoose</h3><!--kg-card-end: html--><p>Configuraremos el esquema para dos colecciones (Task y User) en la rama <code>02-setup-schema</code> usando Mongoose. Los archivos <code>task/model.mjs</code> y <code>user/model.mjs</code> contienen el esquema para las colecciones Task y User, respectivamente. También configuraremos una conexión de base de datos en <code>index.mjs</code> para asegurar que la configuración del esquema funcione correctamente.</p><p>No iré en detalle sobre los modelos y esquemas de Mongoose en este artículo porque están fuera de su alcance.</p><p>Cuando ejecutas el comando <code>node .</code> después de implementar los cambios en <code>02-setup-schema</code>, deberías de ver un resultado similar en la consola como en el fragmento de abajo:</p><pre><code class="language-bash">node .
You are running Node.js v22.13.1
Created user with id 679f1d7f73fbeaf23b2007df
Created task "Task title" for user with id "679f1d7f73fbeaf23b2007df"
</code></pre><p>Puedes ver las diferencias entre <code>01-setup</code> y <code>02-setup-schema</code> a través de la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia 01-setup &lt;&gt; 02-setup-schema en Github</a>. </p><!--kg-card-begin: html--><h3 id="configurar-servicios">3. Configurar los Servicios</h3><!--kg-card-end: html--><p>Luego, creamos los archivos de servicio (<code>task/service.mjs</code> y <code>user/service.mjs</code>) en la rama <code>03-setup-services</code>. Ambos archivos actualmente contienen funciones vacías en el que escribiremos las pruebas más tarde. Estas funciones contendrán la lógica de negocio y también se comunicará con la base de datos. Estamos usando comentarios de <a href="https://jsdoc.app/">JSDoc</a> para escribir parámetros y regresar valores.</p><p>Haz clic en la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia de 02-setup-schema &lt;&gt; 03-setup-services</a> para ver los cambios de código entre <code>02-setup-schema</code> y <code>03-setup-services</code>.</p><!--kg-card-begin: html--><h3 id="configurar-pruebas">4. Configurar las Pruebas</h3><!--kg-card-end: html--><p>En la rama <code>04-set-up-tests</code>, configuramos la base de código para ejecutar las pruebas. Creamos <code>test.setup.mjs</code> el cual contiene el código que será ejecutado antes de que cada archivo de prueba se ejecute.</p><p>En <code>test.setup.mjs</code>, la función <code>connect</code> crea un servidor de MongoDB en memoria y lo conecta con Mongoose para ejecutar las pruebas. La función <code>closeDatabase</code> cierra la conexión de la base de datos y limpia todos los recursos para liberar memoria.</p><p>Las funciones <code>connect</code> y <code>closeDatabase</code> se ejecutan en el hook <code>t.before</code> y en el hook <code>t.after</code> respectivamente. Esto asegura eso, antes que un archivo test se ejecute, una conexión de base de datos se establece a través <code>t.before</code>. Luego de que se hayan ejecutado las pruebas del archivo, la conexión de la base de datos se cae y los recursos usados se limpian a través de <code>t.after</code>.</p><p>En <code>package.json</code>, actualizaremos el script de npm <code>test</code> a <code>node --test --import ./test.setup.mjs</code>. Este comando asegura que Módulo Es <code>test.setup.mjs</code> se pre-cargue y se ejecute a través del comando <code>--import</code> del CLI antes de que cada archivo de prueba se ejecute.</p><p>Luego crearemos los archivos de prueba con pruebas vacías en las carpetas <code>__tests__</code> para <code>user</code> y <code>task</code>. Después de implementar los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/03-setup-services...04-set-up-tests">nuevos cambios en 04-set-up-tests</a>, ejecutar el script <code>test</code> con <code>npm run test</code> debería de mostrar la salida similar al fragmento de abajo:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 8
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 941.768873
</code></pre><p>Todas las pruebas actualmente pasan porque no hay aserciones que fallen. Escribiremos las pruebas con aserciones en la siguiente sección.</p><!--kg-card-begin: html--><h3 id="escribir-pruebas">5. Escribir Pruebas</h3><!--kg-card-end: html--><p>Ahora es tiempo de escribir las pruebas para las funciones en los archivos de service en la rama <code>05-write-tests</code>. Estamos usando la librería de aserción de Node.js para asegurar que los valores regresados de las funciones sean lo que esperamos. Puedes ver las pruebas que hemos escrito cuando comparas <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/04-set-up-tests...05-write-tests">las diferencias entre 04-set-up-tests y 05-write-tests</a>.</p><p>Cuando el script <code>tests</code> se ejecute, todas las pruebas fallan porque no hemos escritos las funciones en los archivos de service todavía. Debería de ver una salida similar al fragmento de abajo cuando ejecutes el script <code>test</code>:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 0
ℹ fail 8
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1202.031961
</code></pre><!--kg-card-begin: html--><h3 id="pasar-pruebas">6. Pasar las Pruebas</h3><!--kg-card-end: html--><p>En <code>06-pass-tests</code>, escribimos las funciones en los archivos de service que pasen las pruebas. Solamente 6 de 7 pruebas pasan cuando el script <code>test</code> se ejecuta porque salteamos la prueba para la función <code>getById</code> en <code>user/service.mjs</code> con <code>t.skip</code>. No hemos terminado la función <code>getById</code> en <code>user/service.mjs</code>. Supuse que podríamos dejarlo como ejercicio.</p><p>Cuando ejecutas el script <code>test</code>, deberías obtener una salida similar en la terminal como el de abajo:</p><pre><code class="language-bash">ℹ tests 7
ℹ suites 4
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 1287.564918
</code></pre><p>Puedes ver el código que escribimos para pasar las pruebas en los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/05-write-tests...06-pass-tests">cambios de código entre 05-write-tests y 06-pass-tests</a>.</p><!--kg-card-begin: html--><h3 id="usa-typescript-opcional">7. Usa TypeScript (Opcional)</h3><!--kg-card-end: html--><p>Si tu intención es ejecutar las pruebas con TypeScript, puedes cambiar a la rama <code>07-with-typescript</code>. Necesitas tener Node.js <code>&gt;=22.6.0</code> instalado porque estamos usando la opción <code>--experimental-strip-types</code> en el <code>test</code>. Para configurar las pruebas que se ejecuten con TypeScript, sigue los siguientes pasos:</p><ol><li>Instala TypeScript usando el comando <code>npm install typescript --save-dev</code> </li><li>Instala tsx usando el comando <code>npm install tsx</code></li><li>Crea un archivo predeterminado <code>tsconfig.json</code> en la raíz del proyecto usando el comando <code>npx tsc --init</code> </li></ol><p>En &nbsp;<code>package.json</code>, actualiza el script <code>test</code> a esto:</p><pre><code class="language-bash">"test": "node --test --experimental-strip-types --import tsx --import ./test.setup.mjs"
</code></pre><ul><li><a href="https://nodejs.org/docs/latest-v22.x/api/cli.html#--experimental-strip-types"><code>--experimental-strip-types</code></a> ayuda a eliminar tipos antes de cada archivo de prueba se ejecute.</li></ul><p>Pre-cargar <code>tsx</code> con el <code>--import</code> ayuda a ejecutar el archivo de TypeScript. Sin él, el ejecutor de pruebas no será capaz de encontrar archivos importados sin la extensión <code>.ts</code>. Por ejemplo, <code>user/model.ts</code> importado con el fragmento de código de abajo no será encontrado.</p><pre><code class="language-typescript">  import { UserModel } from "./model";
</code></pre><p>El resto de los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/06-pass-tests...07-with-typescript">cambios desde 06-pass-tests a 07-with-typescript</a> involucran actualizar los tipos, cambiar las extensiones de archivo de <code>.mjs</code> a <code>.ts</code> y actualizar las declaraciones import.</p><!--kg-card-begin: html--><h2 id="conclusion">Conclusión</h2><!--kg-card-end: html--><p>En esta guía, has aprendido cómo usar el ejecutor de pruebas incorporado de Node.js y por qué es frecuentemente una mejor elección sobre otras librerías y frameworks de pruebas. También has aprendido cómo usar mongodb-memory-server como un reemplazo de un servidor real de MongoDB, así también como por qué es una buena idea usarlo en vez de un servidor real de MongoDB para las pruebas.</p><p>Lo más importante, has aprendido cómo configurar y ejecutar las pruebas en Node.js usando el ejecutor de pruebas de Node.js y mongodb-memory-server. Ahora deberías de saber cómo configurar tus proyectos para que ejecuten las pruebas si usas TypeScript.</p><p>Si encuentras útil a este repositorio <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a>, por favor dale una estrella. Me anima mucho. Gracias.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Un vistazo rápido a Bun 1.0 - Una alternativa a Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido". Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0. ¿Cómo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/un-vistazo-rapido-a-bun-1-0-una-alternativa-a-node-js/</link>
                <guid isPermaLink="false">65c24f33aa1f2203f0eb0f2e</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ bun ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Wed, 14 Feb 2024 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="un-hombre-sabio-me-dijo-una-vez-cuando-empieces-a-comer-bun-panecillo-node-js-se-sentir-ins-pido-">Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido".</h3><p>Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0.</p><p>¿Cómo y por qué es más rápido que Node.js? Me vienen a la mente muchas preguntas.</p><p>Responderé algunas de esas preguntas en este artículo. Y lo haré rápidamente, ya que ahora soy más rápido, al igual que JavaScript, que se prepara con Bun 1.0.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--3-.gif" class="kg-image" alt="But-why-is-that-relevant--3-" width="600" height="400" loading="lazy"></figure><p><strong>Bun es un conjunto de herramientas rápidas todo en uno para ejecutar, crear, probar y depurar JavaScript y TypeScript</strong>, desde un único archivo hasta una aplicación <em>full-stack</em>.</p><p>A continuación algunas cosas que podemos hacer con Bun:</p><h2 id="ejecuta-tu-c-digo-m-s-r-pido-con-bun">Ejecuta tu código más rápido con Bun</h2><p>Ahora no necesitamos herramientas como <code>npm</code>, <code>pnpm</code> o <code>yarn</code> porque Bun es 17 veces mas rápido. Eche un vistazo a los datos mostrados a continuación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png" class="kg-image" alt="266451126-23cbde35-b859-41b5-9480-98b88bf40c44" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/size/w2400/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 2400w" sizes="(min-width: 720px) 720px" width="2680" height="1324" loading="lazy"><figcaption>Comparación de velocidades entre Bun, pnpm, npm y yarn</figcaption></figure><p>Bun tarda solo 0,36 segundos en compilar su código, mientras que tarda unos 6,44 segundos en el caso de pnpm, 10,58 segundos con npm y 12,08 segundos con yarn.</p><h2 id="bun-soporta-hot-reloading">Bun soporta <em>hot reloading</em></h2><p>Bun soporta <em>hot reloading</em> (recarga en caliente) desde el primer momento, por lo que no necesita herramientas como Nodemon. Actualizará automáticamente el servidor cuando se ejecute JavaScript o TypeScript.</p><p>Puede reemplazar el comando <code>npm run</code> con <code>bun run</code> para ahorrar más de 150 ms milisegundos cada vez que ejecuta un comando.</p><p>Aquí un gráfico completo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png" class="kg-image" alt="Screenshot-2023-09-14-at-7.17.45-PM-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1198w" sizes="(min-width: 720px) 720px" width="1198" height="434" loading="lazy"><figcaption>Promedio de tiempos de <em>hot realoding </em>usando diferentes paquetes</figcaption></figure><p>Según el cuadro anterior, el uso de <code>npm</code> tarda unos 176 ms en ejecutarse, <code>yarn</code> tarda unos 131 ms. En el caso de <code>pnpm</code>, se necesitan 259 ms. Sin embargo, en el caso de Bun, se necesitan unos 7 ms. Eso es rápido, ¿no?</p><h2 id="bun-es-un-empaquetador-javascript">Bun es un empaquetador JavaScript</h2><p>Bun también es un empaquetador de JavaScript con el mejor rendimiento de su clase y una API compatible con ESBuild, por lo que no necesitamos cosas como:</p><ul><li>ESBuild</li><li>Webpack</li><li>Parcel, .parcelrc</li><li>Rollup, rollup.config.js</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.gif" class="kg-image" alt="But-why-is-that-relevant--2-" width="1920" height="1080" loading="lazy"></figure><p>Bun ahora soporta Next.js, Remix, Nuxt, Astro, SvelteKit, Nest, SolidStart y Vite.</p><h2 id="bun-es-compatible-con-esm-y-commonjs">Bun es compatible con ESM y CommonJS</h2><p>Otra gran característica de Bun es que podemos usar módulos ES6 y CommonJs juntos en el mismo archivo, lo que no era posible en Node.js.</p><p>Puedes usar <code>import</code> y <code>require()</code> en el mismo archivo:</p><figure class="kg-card kg-code-card"><pre><code class="language-js">import lodash from "lodash";
const _ = require("underscore");</code></pre><figcaption>ESM y CommonJs en el mismo archivo</figcaption></figure><p>Aparte de eso, Bun tiene soporte integrado para las API estándar web que están disponibles en los navegadores, como <code>fetch</code>, junto con la propia API de Bun como <code>Bun.file()</code> para leer un archivo de forma diferida y <code>Bun.Write()</code> para escribir un archivo al sistema de archivos local, que es mucho más simple que Node.js.</p><h2 id="ejemplo-bun-file-">Ejemplo <code>Bun.file()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">const archivo = Bun.file("package.json");
const contenido = await archivo.text();
</code></pre><figcaption>Leemos archivos del sistema de archivos con Bun</figcaption></figure><p>El código anterior leerá el contenido de un archivo <code>package.json</code> y transferirá su contenido a una nueva variable llamada <code>contenido</code>.</p><h2 id="ejemplo-bun-write-">Ejemplo <code>Bun.write()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">await Bun.write("index.html", "&lt;html/&gt;");
await Bun.write("index.html", Buffer.from("&lt;html/&gt;"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", 
await fetch("https://ejemplo.com/"));</code></pre><figcaption>Escribimos archivos en el sistema de archivos</figcaption></figure><p>En el código anterior, <code>Bun.write()</code> escribirá la cadena <code>"&lt;html/&gt;"</code>, o copiará el contenido del archivo <code>home.html</code> en el archivo <code>index.html</code>. Si tenemos que recuperar datos, obtendrá los resultados de una API web externa y escribirá el contenido en un archivo <code>index.html</code>.</p><h2 id="-por-que-bun-es-tan-r-pido">¿Por que Bun es tan rápido?</h2><p>Bun es rápido porque usa el motor JavaScriptCore, mientras que Node.js usa el motor JavaScript V8. El primero se ha optimizado para un tiempo de inicio más rápido.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png" class="kg-image" alt="But-why-is-that-relevant" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/But-why-is-that-relevant.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/But-why-is-that-relevant.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="900" loading="lazy"><figcaption>Bun usa JavaScriptCore | Node usa V8</figcaption></figure><p>Si deseas hacer las cosas más rápido, debería considerar reemplazar Node.js con Bun.</p><h2 id="-c-mo-empezar-a-usar-bun">¿Cómo empezar a usar Bun?</h2><p>Puedes instalar Bun en sistemas MacOS y Linux usando <code>npm</code>:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">npm install -g bun</code></pre><figcaption>Comando para instalar Bun en MacOs y distribuciones Linux</figcaption></figure><p>Ahora ya está todo listo. Para instalar un paquete <code>npm</code>, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun install &lt;nombre-paquete&gt;</code></pre><figcaption>Comando para instalar paquetes usando Bun</figcaption></figure><p>Para iniciar una aplicación, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun run dev</code></pre><figcaption>Ejecutar una app Next.js</figcaption></figure><p>Para todo lo que pueda necesitar solo reemplace <code>npm</code> con <code>bun</code>.</p><p>Sin embargo, Bun sólo está listo para producción en los sistemas operativos MacOS y Linux. La versión de Windows aún es experimental. Por el momento, solo se admite el entorno de ejecución de JavaScript para Windows, y no el administrador de paquetes, el empaquetador ni el entorno de pruebas. <a href="https://bun.sh/docs/installation#windows">Puedes leer más al respecto aquí</a>.</p><h1 id="conclusi-n">Conclusión</h1><p>Este artículo muestra cómo puedes utilizar Bun como alternativa a Node.js y acelerar su tiempo de desarrollo.</p><p>También puedes ver mi vídeo sobre <a href="https://www.youtube.com/watch?v=q5UKY_dCmh4"><strong>El asesino de Node.js está aquí — Primer vistazo a Bun 1.0</strong></a><strong> (en inglés)</strong>.</p><p>Gracias por leer.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Construyendo una API REST con Node + Fastify + Sequelize + PostgreSQL ]]>
                </title>
                <description>
                    <![CDATA[ En las próximas líneas vamos a describir los pasos para realizar la implementación de una API REST que realizará las funciones de la capa de backend y será responsable de la gestión de datos de un sistema de gestiṍn de turnos o tickets.  Si deseas profundizar en cuanto a ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/construyendo-una-api-rest-con-node-fastify-sequelize-postgresql/</link>
                <guid isPermaLink="false">65590ef2bcc2a003e70e2db7</guid>
                
                    <category>
                        <![CDATA[ api rest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fastify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ sequelize ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgresql ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leonardo José Castillo Lacruz ]]>
                </dc:creator>
                <pubDate>Sat, 30 Dec 2023 02:29:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/12/btmJOTjifO9r_2560_1440.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>En las próximas líneas vamos a describir los pasos para realizar la implementación de una API REST que realizará las funciones de la capa de backend y será responsable de la gestión de datos de un sistema de gestiṍn de turnos o tickets. </p><p>Si deseas profundizar en cuanto a como funciona una API REST, sus elementos y particularidades, puedes consultar <a href="https://www.freecodecamp.org/espanol/news/consumiendo-una-api-rest-con-react-js/">este artículo de freecodecamp.org</a>, que describe de forma detallada los conceptos anteriormente mencionados.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/12/image-2.png" class="kg-image" alt="image-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/12/image-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/12/image-2.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/12/image-2.png 1024w" sizes="(min-width: 720px) 720px" width="1024" height="1024" loading="lazy"></figure><p>Cuando construimos una API REST, debemos identificar que datos para gestionar, en nuestro caso, vamos a tomar como ejemplo un sistema de gestión de tickets, que tendría un modelo de datos similar al que vemos en el siguiente diagrama:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/12/image.png" class="kg-image" alt="image" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/12/image.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2023/12/image.png 659w" width="659" height="390" loading="lazy"><figcaption>Modelo entidad-relación. Sistema de turnos/tickets</figcaption></figure><p>Tomando en cuenta lo indicado, a partir del modelo entidad-relación anterior, es importante identificar los elementos que van a actuar como componentes de nuestra API REST.</p><h2 id="elementos-componentes-de-una-api-rest">Elementos componentes de una API REST</h2><p>Vamos a identificar 3 componentes principales en la construcción de una API REST, estos son: </p><ul><li>Modelos, que serán las representación de las entidades que iremos a gestionar en la API, es la abstracción de los datos del mundo real al mundo digital.</li><li>Controladores, responsables de implementar las operaciones a realizar sobre los modelos, a veces denominada capa de lógica de negocios.</li><li>Rutas, definiciones de como nuestra API puede interactuar con el mundo exterior, es decir a través de las rutas definimos la comunicación entre la implementación que vamos a realizar con los servicios o herramientas que irán a consumir lo que realicemos.</li></ul><p>Para construir esta API vamos a usar NodeJS, que es el entorno de ejecución de javascript para backend. </p><h3 id="definiendo-a-nodejs">Definiendo a NodeJS</h3><p>Según la web oficial de <a href="https://nodejs.org/es/about" rel="noopener ugc nofollow">nodejs.org</a>, la definición de Node es:</p><blockquote><em><em>Ideado como un entorno de ejecución de JavaScript orientado a eventos asíncronos, Node.js está diseñado para crear aplicaciones network escalables.</em></em></blockquote><p>En el siguiente material tendrás algunas orientaciones básicas de como funciona y como realizar la instalación del mismo.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/BA1-NU5edwQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Introducción a Node.js: Guía para principiantes" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p> </p><h3 id="qu-es-fastify">Qué es Fastify</h3><p>Partiendo de los elementos indicados como componentes de una API, vamos a explicar que paquetes vamos a utilizar para la implementacion de cada uno de ellos. Comencemos por el responsable de las rutas o mejor en forma general, por la comunicación y transporte de datos.</p><p>Es a través de este proceso (comunicación y transporte) que nuestra API REST &nbsp;va a recibir y enviar datos a quien esté consumiendo el servicio. Esto se hace a través de rutas.</p><p>Para esta tarea tenemos varias opciones, como usar las clases nativas de NodeJS, usar el framework expressjs o &nbsp;en nuestro caso usar el framework fastify. Te preguntaras por qué Fastify?. Varias razones: simplicidad, rapidez y escabilidad del framework.</p><p>Primero vamos a crear nuestro proyecto node, con la siguiente instrucción:</p><pre><code>npm init</code></pre><p>Ahora avancemos a la instalación de fastify, esta muy simple, sólo ejecutanos el siguiente comando y con ello ya en nuestro proyecto podemos usar sus métodos y funcionalidades, pero comencemos por crear el proyecto:</p><pre><code>npm install fastify</code></pre><p>Ahora procedemos a construir el esqueleto de nuestra API.</p><h2 id="construyendo-los-elementos-de-nuestra-api-rest">Construyendo los elementos de nuestra API REST</h2><p>Empecemos por el archivo principal, el cual será: <code>index.js</code> El contenido del archivo <code>index.js</code> será:</p><pre><code>import Fastify from 'fastify';

const fastify = Fastify({
    logger: true
});

// Ruta inicial
fastify.get('/', async function handler (req, res) {
    return { hello: 'world' };
});
  
// Ejecución de la aplicación
try {
    await fastify.listen({ port: 3000 });
} catch (err) {
    fastify.log.error(err);
    process.exit(1);
}</code></pre><p>Con lo anterior, ya tenemos en pocas líneas, una API funcional, que solo tiene una ruta, pero que en esencia está completa. Ahora pasemos a la extensión de sus rutas.</p><h3 id="definiendo-las-rutas-b-sicas">Definiendo las rutas básicas</h3><p>Procedemos entonces a definir las rutas que nuestra API va a implementar, en este caso creamos un nuevo archivo llamado <code>routes.js</code>, en el cual definimos los CRUDs de cada uno de nuestros modelos, siendo que CRUD será (C-reate, R-ead, U-pdate, D-elete), en español serán las operaciones de Inserción, Lectura, Actualización y Borrado.</p><p>El archivo quedará de esta forma: </p><pre><code>const rutas = [
    {
        method: "POST",
        url: "/usuarios",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - POST'});
        }
    },
    {
        method: "GET",
        url: "/usuarios",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - GET'});
        }
    },
    {
        method: "PUT",
        url: "/usuarios/:id",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - PUT'});
        }
    },
    {
        method: "DELETE",
        url: "/usuarios/:id",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - DELETE'});
        }
    }
]

export default rutas;</code></pre><p>Observa que algunas rutas tienen <code>:/id</code>, esto lo explicaremos en detalle más adelante. </p><p>Con las rutas ya definidas, el siguiente paso será definir los modelos, notese que en el archivo anterior, dejamos la propiedad <code>handler</code> apuntando a una función básica que siempre retorna OK.</p><pre><code>handler: (req,res) =&gt; {
	res.status(200).send('OK');
}</code></pre><p>Esto significa que por ahora no tenemos ningún proceso asociado a las rutas, pero hemos dejado ya la estructura hecha. La implementación será realizada más adelante.</p><p>Incorporemos las rutas a nuestro archivo principal <code>index.js</code>, quedando este de la siguiente forma:</p><pre><code>import Fastify from 'fastify';
import rutas from './rutas.js';
import cors from '@fastify/cors';

const fastify = Fastify({logger:true});
await fastify.register(cors, {

});

//POST - Inserciones                C-REATE
//GET - Consulta                    R-EAD
//PUT, PATCH - Actualizaciones      U-PDATE
//DELETE - Borrado                  D-ELETE

fastify.get("/",async function(req, res) {
    return { hello: 'world'};
});

//Incorporación de las rutas
rutas.forEach((ruta) =&gt; {
    fastify.route(ruta);
});

try {
    fastify.listen({port:3500});
} catch(erro) {
    console.log(erro);
}
</code></pre><p>En el siguiente material podrás visualizar el paso de la construcción que hemos hecho hasta ahora.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/DuUMepfA0Z8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="API REST con NodeJS + Fastify: Crea tu primera API RESTful desde cero" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><h2 id="modelos">Modelos</h2><p>Acá vamos a definir los datos que nuestra API procesará, tomemos la primera entidad "Usuarios" y definamos su modelo, para ello nos vamos a apoyar en <code>sequelize</code>, que nos permite hacer una definición que luego se reflejará en la base de datos, esto debido a que Sequelize actua como un ORM (Object Relation Mapping).</p><h3 id="pero-qu-es-un-orm-object-relation-mapping">Pero qué es un ORM - Object Relation Mapping?</h3><p>Tomando lo que <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">https://en.wikipedia.com</a> nos indica, podemos citar lo que es un ORM:</p><blockquote>Un ORM (Object-Relational Mapping) es una técnica de programación que permite la conversión de datos entre una base de datos relacional y un lenguaje de programación orientado a objetos. En otras palabras, un ORM es una herramienta que ayuda a simplificar la traducción entre los dos paradigmas: objetos y tablas de bases de datos relacionales. Puede utilizar definiciones de clases (modelos) para crear, mantener y proporcionar acceso completo a los datos de los objetos y su persistencia en la base de datos.</blockquote><h3 id="instalando-sequelizer">Instalando Sequelizer</h3><p>Para realizar la instalación de Sequelizer, necesitamos ejecutar sólo este comnpm install sequelizerando:</p><pre><code>npm install sequelizer</code></pre><p>Ejecutando lo anterior, tenemos ya disponible el paquete en nuestro proyecto, es momento de conectar nuestra base de datos, para ello creamos un nuevo archivo llamado <code>db.js</code> y colocamos los parámetros de conexión correspondientes:</p><pre><code class="language-Javascript">/* eslint-disable require-jsdoc */
import Sequelize from 'sequelize';

/*
Clase de conexión a la base de datos
*/
class DBInstance {
	constructor() {
		const dbCfg = {
			user: '&lt;usuario_base_datos&gt;',
			host: '&lt;ip_o_dns_servidor&gt;',
			database: '&lt;nombre_base_datos&gt;',
			password: '&lt;clave_usuario_base_datos&gt;',
			port: 5432,
		};
		this.sequelize = new Sequelize(dbCfg.database, dbCfg.user, dbCfg.password, {
			host: dbCfg.host,
			dialect: 'postgres',
			logging: false,
		});
	}
}

export default new DBInstance().sequelize;
</code></pre><p>Con lo anterior, ya tenemos conexión a nuestra base de datos. Ajustamos nuestro archivo <code>index.js</code> para importar este proceso de conexión y dejarlo ejecutandose cuando sea iniciada la API. Quedando su código de esta forma:</p><pre><code>import Fastify from 'fastify';
import db from './db.js';
import rutas from './rutas.js';
import cors from '@fastify/cors';

const fastify = Fastify({logger:true});
await fastify.register(cors, {

});

//POST - Inserciones                C-REATE
//GET - Consulta                    R-EAD
//PUT, PATCH - Actualizaciones      U-PDATE
//DELETE - Borrado                  D-ELETE

// eslint-disable-next-line no-unused-vars
fastify.get('/',async function(req, res) {
	return { hello: 'world'};
});

//Incorporación de las rutas
rutas.forEach((ruta) =&gt; {
	fastify.route(ruta);
});

async function database() {
	try {
		await db.sync();
		console.log('Conectado a la base de datos');
	} catch(e) {
		console.log(e);
	}
}

try {
	fastify.listen({port:3500});
	database();
} catch(erro) {
	console.log(erro);
}</code></pre><p>Observa que hemos creado una función asincrona llamada <code>database()</code> y luego al iniciar la API, la invocamos para que se realice la conexión y sincronización del modelo.</p><p>Ahora procedemos a crear el modelo, recordando que un modelo es la representación de los datos que vamos a gestionar del mundo real en nuestra API. </p><p>Comencemos por el modelo de Usuarios:</p><pre><code>import sequelize from "sequelizer";

const User = sequelize.define("User", {
    id : {
        type: sequelize.STRING,
        allowNull: false,
        primaryKey: true,
    },
    fullname: {
        type: sequelize.STRING,
        allowNull: false,
    },
    password: {
        type: sequelize.STRING,
        allowNull: false,
    },
});

export default User;</code></pre><p>Observa que cada propiedad del objeto que define el modelo, corresponde con el nombre del campo que definimos en nuestro modelo de entidad-relación al inicio del documento, el nombre de cada propiedad representa cada campo, así que debemos tener cuidado con el nombre que le indiquemos, mi recomendación usar letras minusculas, no usar caracteres especiales.</p><p>En el caso de password, vamos usar un paquete adicional, para poder encriptar el contenido de la misma, recordando que por seguridad, los datos de claves no se deben guardar de forma plana o legible en la base de datos.</p><p>Para lograr que nuestro password quede guardado de forma segura, hacemos uso del paquete <code>bcrypt</code>, el cual nos permite codificar el valor enviado por el usuario y luego con un método propio del paquete podemos validar si clave es la guardada, de esta forma el modelo de Usuarios queda implementado con el siguiente código:</p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import bcrypt from 'bcrypt';
import db from '../db.js';


const UserModel = db.define('users', {
  id: {
    type: sequelize.STRING,
    allowNull: false,
    primaryKey: true,
  },
  fullname: {
    type: sequelize.STRING,
    allowNull: false,
  },
  password: {
    type: sequelize.STRING,
    allowNull: false,
  },
}, {
  hooks: {
    beforeCreate: (user) =&gt; {
      const salt = bcrypt.genSaltSync();
      user.password = bcrypt.hashSync(user.password, salt);
    },
  },
});

UserModel.prototype.validPassword = function(password) {
  return bcrypt.compareSync(password, this.password);
};

export default UserModel;</code></pre><figcaption>Modelo de Usuarios</figcaption></figure><p>Para el caso del modelo de tiendas o comercios, siguiendo lo definido anteriormente, el modelo queda representado con el siguiente código:</p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import db from '../db.js';

const StoreModel = db.define('stores', {
  id: {
    type: sequelize.INTEGER,
    autoIncrement: true,
    allowNull: false,
    primaryKey: true,
  },
  store_name: {
    type: sequelize.STRING,
    allowNull: false,
  },
  category_store: {
    type: sequelize.STRING,
    allowNull: false,
  },
});


export default StoreModel;</code></pre><figcaption>Modelo de Tiendas/Comercios</figcaption></figure><p>Algunas diferencias notorias, en el caso de id, usamos una propiedad dentro del objeto <code>id</code> que es <code>autoIncrement</code>, la cual define que el campo en la base de datos será del valor automático e incremental, de esta forma la base de datos asignará el id correspondiente. Otro punto interesante es el tipo de datos, en el caso de <code>id</code> usamos el tipo <code>INTEGER</code>, para definir que es un número entero.</p><p>Pasemos ahora al modelo de Tickets o Turnos, hacemos la implementación, recordando que este modelo se relaciona con Usuarios y Tiendas, de forma que un <em>Usuario </em>tiene N <em>Tickets </em>y una Tienda también tiene N <em>Tickets,</em> de esta forma el modelo implementado será: </p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import db from '../db.js';
import UserModel from './Users.js';
import StoreModel from './Stores.js';

const TicketModel = db.define('tickets', {
  id: {
    type: sequelize.STRING,
    allowNull: false,
    primaryKey: true,
  },
  date_time: {
    type: 'TIMESTAMP',
    allowNull: false,
  },
  status: {
    // eslint-disable-next-line new-cap
    type: sequelize.ENUM(['Creado', 'Confirmado', 'Atendido', 'Cancelado',
      'En progreso']),
    allowNull: false,
  },
  observation: {
    type: sequelize.TEXT,
    allowNull: false,
  },
  end_date_time: {
    type: 'TIMESTAMP',
    allowNull: false,
  },
});

UserModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'user_id',
    type: sequelize.STRING,
    allowNull: false,
  },
});

StoreModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'store_id',
    type: sequelize.INTEGER,
    allowNull: false,
  },
});


export default TicketModel;
</code></pre><figcaption>Modelo de Turnos o Tickets</figcaption></figure><p>En este modelo tenemos algunas particularidades que valen la pena analizar:</p><ul><li>Tenemos nuevos tipos de datos: <code>TEXT</code>para almacenar grandes cantidad de datos (mayores a 255 caracteres), <code>ENUM</code> para definir un conjunto de valores cerrados para un campo en particular. <code>TIMESTAMP</code> para definir campos de tipo fecha/hora.</li><li>Relaciones, en este modelo le decimos a <code>sequelize</code> que queremos relacionar los modelos en este segmento de código:</li></ul><pre><code>UserModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'user_id',
    type: sequelize.STRING,
    allowNull: false,
  },
});

StoreModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'store_id',
    type: sequelize.INTEGER,
    allowNull: false,
  },
});</code></pre><p>Observa que se indica que el modelo Usuarios (<code>UserModel</code>) tiene muchos Tickets con la instrucción: <code>hasMany</code>, lo mismo sucede en el caso de Tiendas (<code>StoreModel</code>), le indicamos que va a tener múlples Tickets.</p><p>Con ellos hemos finalizado los modelos a implementar, ahora pasemos a la lógica de negocios.</p><h2 id="controladores">Controladores</h2><p>Estos elementos tan importantes a la hora de construir nuestra API REST, son los responsables de implementar lo que denominamos la lógica de negocios, es decir ellos reciben los datos enviados por quienes consumen el servicio o la API, los procesan, envian a la capa de datos cuando corresponde y retornan una respuesta. </p><p>De acuerdo con lo anterior, entonces en los controladores donde vamos a implementar el famoso CRUD (Create, Read, Update and Delete), el cual ya citamos anteriormente. Ahora bien, definamos la anatomía de un controlador:</p><pre><code>import Model from "../models/Model.js";

class ModeloController {
    constructor() {

    }
    
    //Creación de registros
    async create (req, res)  {
    }
    
    //Consulta de todos los registros del modelo
    async getAll(req, res) {
    }

	//Consulta de un registro en particular
    async getOne(req, res) {
    }
    
    //Actualización de un registro
    async update(req, res) {
    }
    
    
    //Borrado de un registro
    async delete(req, res) {
    }
    
 }
    </code></pre><p>Notemos que el controlador implementar como comentarmos anteriormente cada una de las operaciones del CRUD, que la API va a realizar para cada uno de los modelos construidos, de esta forma, vamos a tener que crear un controlador para usuarios, otro para tiendas y uno más para los tickets o turnos.</p><p>En este material realizamos la implementación de los modelos y parte de los controladores:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/pn7Vyj3w2wc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Creando capas de modelos y controladores en una API REST con NodeJS, Fastify, PostgreSQL y Sequelize" name="fitvid2"></iframe>
          </div>
        </div>
      </figure><p>Ahora para cada modelo que hemos definido en nuestra API, construimos sus controladores, quedando su código de esta forma:</p><ul><li>UsersController</li></ul><pre><code>/* eslint-disable require-jsdoc */
import UserModel from '../models/Users.js';

class UsersController {
  constructor() {

  }

  async create(req, res) {
    try {
      const userModel = await UserModel.create(req.body);

      if (userModel) {
        res.status(200).send({status: true, id: userModel.id});
      }
    } catch (e) {
      res.status(500).send({error: e});
    }
  }

  async getAll(req, res) {
    try {
      const where = {...req.query};
      const usuarios = await UserModel.findAll({where});
      res.status(201).send(usuarios);
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar usuarios'},
      );
    }
  }

  async getOne(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.findByPk(id);

      if (userModel) {
        res.status(201).send(userModel);
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar el usuario'},
      );
    }
  }

  async update(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.update(req.body,
          {where: {id}});

      if (typeof (userModel[0]) !== 'undefined' &amp;&amp; userModel[0] === 1) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al actualizar el usuario'},
      );
    }
  }

  async delete(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.destroy({where: {id}});

      if (userModel) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al intentar borrar un usuario'},
      );
    }
  }
}

export default new UsersController();
</code></pre><p>Del código anterior podemos resaltar algunas caracteristicas:</p><ul><li>Todos los métodos son asincronos, es decir por ser operaciones de base de datos, estos procesos deben esperar resultados y recordamos que Javascript <em>no espera a nadie </em>por lo tanto usamos las palabras reservadas <code>async</code> e <code>await</code> para lograr ese objetivo.</li><li>Encerramos el procesamiento o la lógica de cada operación entre las palabras <code>try</code> y <code>catch</code> de forma tal que cualquier error, lo podamos capturar y retornar a quien nos consume los servicios.</li><li>En cada uno de los métodos de nuestros controladores, nos vamos a apoyar en métodos de <em>Sequelize</em>, que nos van a facilitar el acceso y la gestión de los datos a nivel de base de datos. En la creación usamos <code>create</code>, en la búsqueda usamos <code>findAll</code>, para conseguir un registro en particular usamos <code>findByPk</code>, para actualizar usamos <code>update</code> y para borrar usamos <code>destroy</code>.</li><li>En las operaciones que envuelven acceso a un registro en particular usamos del objeto <code>req</code> la propiedad <code>params</code>, es decir usamos <code>req.params</code> para obtener el id del registro. Este parámetro lo definimos en la ruta.</li><li>Cuando hacemos operaciones de envio de datos, sea en la creación o en la actualización, el cuerpo o data la recibimos en lo que se denomina el <code>body</code> de la requisición, esto se obtiene con <code>req.body</code>.</li></ul><p>Veamos como ha quedado el controlador de tiendas:</p><pre><code>import StoreModel from '../models/Stores.js';


/* eslint-disable require-jsdoc */
class StoreController {
  constructor() {

  }

  async create(req, res) {
    try {
      const storeModel = await StoreModel.create(req.body);

      if (storeModel) {
        res.status(201).send({status: true, id: storeModel.id});
      }
    } catch (e) {
      res.status(500).send(e);
    }
  }

  async getAll(req, res) {
    try {
      const where = req.query;

      const tiendas = await StoreModel.findAll({where});
      res.status(201).send(tiendas);
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar tiendas'},
      );
    }
  }

  async getOne(req, res) {
    try {
      const {id} = req.params;

      const storeModel = await StoreModel.findByPk(id);
      if (storeModel) {
        res.status(201).send(storeModel);
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar la tienda'},
      );
    }
  }

  async update(req, res) {
    try {
      const {id} = req.params;
      const data = {...req.body};

      delete data.id;

      const storeModel = await StoreModel.update(data,
          {where: {id}});

      if (typeof (storeModel[0]) !== 'undefined' &amp;&amp; storeModel[0] === 1) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al actualizar la tienda'},
      );
    }
  }

  async delete(req, res) {
    try {
      const {id} = req.params;

      const storeModel = await StoreModel.destroy({where: {id}});

      if (storeModel) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al intentar borrar una tienda'},
      );
    }
  }
}

export default new StoreController();</code></pre><p>El controlador es bien similar al de usuarios, implementado en la clase <code>UserController</code>, solo en el método de actualización (<code>update</code>), agregamos está linea: <code>delete data.id;</code> para evitar que sea modificar el id interno del registro.</p><p>El controlador de Turnos, sigue a continuación, este controlador también tiene la protección para evitar que el campo autonumérico sea modificado en el método de actualización (<code>update</code>). </p><pre><code>import TicketModel from '../models/Tickets.js';

/* eslint-disable require-jsdoc */
class TicketController {
	constructor() {

	}

	async create(req, res) {
		try {
			const ticketModel = await TicketModel.create(req.body);

			if (ticketModel) {
				res.status(201).send({status: true, id: ticketModel.id});
			}
		} catch (e) {
			res.status(500).send(e);
		}
	}

	async getAll(req, res) {
		try {
			const where = req.query;

			const tickets = await TicketModel.findAll({where});
			res.status(201).send(tickets);
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al consultar tickets'},
			);
		}
	}

	async getOne(req, res) {
		try {
			const {id} = req.params;

			const ticketModel = await TicketModel.findByPk(id);
			if (ticketModel) {
				res.status(201).send(ticketModel);
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al consultar el ticket'},
			);
		}
	}

	async update(req, res) {
		try {
			const {id} = req.params;
			const data = {...req.body};
			delete data.id;

			const ticketModel = await TicketModel.update(data,
				{where: {id}});

			if (typeof (ticketModel[0]) !== 'undefined' &amp;&amp; ticketModel[0] === 1) {
				res.status(201).send({
					status: true,
				});
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al actualizar el ticket'},
			);
		}
	}

	async delete(req, res) {
		try {
			const {id} = req.params;

			const ticketModel = await TicketModel.destroy({where: {id}});

			if (ticketModel) {
				res.status(201).send({
					status: true,
				});
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al intentar borrar un ticket'},
			);
		}
	}
}

export default new TicketController();
</code></pre><p>Con esto hemos finalizado los controladores.</p><h2 id="rutas-actualizadas">Rutas actualizadas</h2><p>Ahora es momento de revisar como llamamos todo lo implementado en nuestras rutas, recordando que al inicio generamos las rutas para el módelo de usuarios, pero llamando a métodos genéricos en lugar de nuestros controladores, con ellos implementados, podemos ajustar el código, el cual queda de la siguiente forma:</p><pre><code>import UsersController from './controllers/Users.js';
import StoreController from './controllers/Stores.js';
import TicketController from './controllers/Tickets.js';

const rutas = [
	{
		method: 'POST',
		url: '/usuarios',
		handler: UsersController.create,
	},
	{
		method: 'GET',
		url: '/usuarios',
		handler: UsersController.getAll,
	},
	{
		method: 'GET',
		url: '/usuarios/:id',
		handler: UsersController.getOne,
	},
	{
		method: 'PUT',
		url: '/usuarios/:id',
		handler: UsersController.update,
	},
	{
		method: 'DELETE',
		url: '/usuarios/:id',
		handler: UsersController.delete,
	},

	/* Rutas de tiendas */
	{
		method: 'POST',
		url: '/tiendas',
		handler: StoreController.create,
	},
	{
		method: 'GET',
		url: '/tiendas',
		handler: StoreController.getAll,
	},
	{
		method: 'GET',
		url: '/tiendas/:id',
		handler: StoreController.getOne,
	},
	{
		method: 'PUT',
		url: '/tiendas/:id',
		handler: StoreController.update,
	},
	{
		method: 'DELETE',
		url: '/tiendas/:id',
		handler: StoreController.delete,
	},

	/* Rutas de turnos */
	{
		method: 'POST',
		url: '/turnos',
		handler: TicketController.create,
	},
	{
		method: 'GET',
		url: '/turnos',
		handler: TicketController.getAll,
	},
	{
		method: 'GET',
		url: '/turnos/:id',
		handler: TicketController.getOne,
	},
	{
		method: 'PUT',
		url: '/turnos/:id',
		handler: TicketController.update,
	},
	{
		method: 'DELETE',
		url: '/turnos/:id',
		handler: TicketController.delete,
	},
];

export default rutas;</code></pre><p>Interesante que nuestro archivo raiz <code>index.js</code> no sufre ninguna alteración, esto debido al grado de encapsulamiento y desacoplamiento que hemos implementado.</p><p>Con esto ya tenemos una API Rest funcional, implementada con NodeJS, Fastify, Sequelize y PostgreSQL.</p><p>Puedes verificar la implementación de los controladores y de todos sus métodos en este material:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/vvlWMU7mbiA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Construyendo una API RESTful con Node, Fastify, Sequelize y Postgres: Parte 3 - Finalizando el CRUD" name="fitvid3"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo desplegar una aplicación Node.js: Desde la configuración del servidor hasta el entorno de producción ]]>
                </title>
                <description>
                    <![CDATA[ En este tutorial, aprenderemos todo lo que necesitamos saber antes de implementar una aplicación Node en un servidor de producción. Comenzaremos alquilando un servidor en Digital Ocean. Luego configuraremos este servidor, nos conectaremos a él, instalaremos Nginx y lo configuraremos, extraeremos o crearemos nuestra aplicación Node y la ejecutaremos como ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-desplegar-una-aplicacion-node-js-desde-la-configuracion-del-servidor-hasta-el-entorno-de-produccion/</link>
                <guid isPermaLink="false">64460d852ef44808032faf6f</guid>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Mon, 01 May 2023 00:56:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/603a54d9a675540a22924662.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/deploy-nodejs-app-server-to-production/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Deploy a Node.js App – From Server Setup to Production</a>
      </p><p>En este tutorial, aprenderemos todo lo que necesitamos saber antes de implementar una aplicación Node en un servidor de producción.</p><p>Comenzaremos alquilando un servidor en Digital Ocean. Luego configuraremos este servidor, nos conectaremos a él, instalaremos Nginx y lo configuraremos, extraeremos o crearemos nuestra aplicación Node y la ejecutaremos como un proceso.</p><p>Como puedes ver, hay mucho que hacer y será un tutorial lleno de acción. Así que comencemos sin perder tiempo.</p><p>Debes tener algunos conocimientos básicos sobre cómo funciona la Terminal y cómo trabajar con Vi/Vim antes de comenzar. Si no estás familiarizado con los comandos básicos, te aconsejo que los leas un poco.</p><p>Ejecutaré los comandos en MacOS. Si quieres seguir este tutorial en Windows, puedes usar Powershell o algún otro emulador de Unix de tu elección.</p><p>Aunque usaré Node.js como plataforma de nuestra aplicación de ejemplo, la mayoría de los pasos son los mismos para cualquier aplicación web.</p><h2 id="-por-qu-digital-ocean"><strong>¿Por qué Digital Ocean?</strong></h2><p>Elijo Digital Ocean porque es barato y la interfaz es realmente fácil de usar, en comparación con AWS. Además, se incluye un crédito de $100 en el paquete de estudiante de GitHub para que no tengas que pagar nada durante un par de meses. Es ideal para implementar un curso o un proyecto de pasatiempos.</p><p>Tiene un concepto llamado Droplets, que es básicamente tu parte de un servidor. Puedes imaginar el servidor como un apartamento del que eres propietario o un apartamento alquilado.</p><p>Los droplets funcionan con la ayuda de máquinas virtuales que se ejecutan en el servidor. Entonces, un Droplet es tu máquina virtual en un servidor compartido. Dado que es una máquina virtual, su uso compartido de CPU y memoria se puede aumentar fácilmente, generalmente invirtiendo más dinero en tu proveedor.</p><h2 id="c-mo-crear-un-proyecto-de-digital-ocean"><strong>Cómo crear un proyecto de Digital Ocean</strong></h2><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-3.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-3.png" width="600" height="400" loading="lazy"></figure><p>Supongo que ya te has registrado e iniciado sesión en Digital Ocean antes de continuar. Primero debemos crear un proyecto que contenga nuestros droplets. Hagamos clic en el botón de nuevo proyecto en el menú del lado izquierdo. Te pedirá que nombres tu proyecto.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-22-at-13.35.06.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-22-at-13.35.06.png" width="600" height="400" loading="lazy"></figure><p>Introduce el nombre que quieras. También te preguntará si quieres mover algún recurso, pero por ahora simplemente haz clic en Omitir; crearemos el droplet más tarde.</p><h2 id="c-mo-crear-un-droplet-en-digital-ocean"><strong>Cómo crear un droplet en Digital Ocean</strong></h2><p>Vamos a crear nuestro droplet haciendo clic en el botón Comenzar.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-4-1024x593.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-4-1024x593.png" width="600" height="400" loading="lazy"></figure><p>Después de hacer clic en el botón, nos pedirá que elijamos una imagen de VM (Máquina virtual).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-22-at-13.12.43-1024x567.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-22-at-13.12.43-1024x567.png" width="600" height="400" loading="lazy"><figcaption>Elegir una imagen</figcaption></figure><p>En esta página, seleccionaré Ubuntu 20.04, ya que es la última versión de LTS en el momento en que escribo esta publicación. LTS significa "Soporte a largo plazo" (por sus siglas en inglés). Lo mejor es optar por la versión LTS para proyectos reales, porque el proveedor garantiza que será compatible y mantenido durante mucho tiempo. Esto significa que no tendrás problemas a largo plazo.</p><p>Elegí Ubuntu y te lo recomendaría, ya que es la distribución de Linux más utilizada. Esto significa que también es más fácil encontrar respuestas a tus dudas futuras.</p><p>También puedes optar por tener una CPU dedicada si la necesitas. Si estás construyendo tu propia startup o cualquier proyecto comercial, te recomendaría leer esta <a href="https://www.digitalocean.com/docs/droplets/resources/choose-plan/">publicación</a> que contiene instrucciones detalladas sobre cómo elegir la opción adecuada para ti.</p><p>Seguiré con la opción más barata en este caso.</p><p>Luego, deberás seleccionar una región del centro de datos. Debes elegir el que esté más cerca de ti para minimizar el retraso de la red.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-2-1024x519.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-2-1024x519.png" width="600" height="400" loading="lazy"><figcaption>Seleccionar un centro de datos</figcaption></figure><p>A continuación, seleccionemos Claves SSH como el Método de autenticación, ya que es mucho más seguro que la autenticación de contraseña básica.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-5-1024x459.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-5-1024x459.png" width="600" height="400" loading="lazy"><figcaption>Método de autenticación</figcaption></figure><p>Para conectarnos al servidor necesitamos generar una nueva clave SSH en nuestro propio dispositivo y agregarla a Digital Ocean.</p><h2 id="c-mo-generar-una-clave-ssh"><strong>Cómo generar una clave SSH</strong></h2><p>Generaré la clave en mi dispositivo macOS. Si estás utilizando Windows, puedes consultar <a href="https://phoenixnap.com/kb/generate-ssh-key-windows-10">este</a> artículo. Abre tu terminal y muévete a la carpeta ssh:</p><pre><code>cd ~/.ssh</code></pre><p>Luego crea tu clave SSH:</p><pre><code>ssh-keygen</code></pre><p>Si tu computadora dice que no conoce este comando, debes instalarlo a través de brew.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-7-1024x140.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-7-1024x140.png" width="600" height="400" loading="lazy"></figure><p>Te pedirá que asignes un nombre al archivo e ingreses una frase de contraseña. No ingreses un nombre, solo presiona enter y sigue con los valores predeterminados. Deberías tener estos archivos generados. He nombrado el mío digital-ocean-ssh en esta captura de pantalla, así que no te confundas con eso.</p><pre><code>❯ lsid_dsa      id_rsa      known_hosts</code></pre><p>Nuestra clave pública es el <code>id_dsa</code> y el <code>id_rsa</code> es nuestra clave privada. Si olvidas cuál es la privada, siempre puedes imprimir una de ellas para verla.</p><h2 id="c-mo-agregar-tu-clave-ssh-a-digital-ocean"><strong>Cómo agregar tu clave SSH a Digital Ocean</strong></h2><p>Ahora queremos copiar nuestra clave pública y subirla a Digital Ocean para que sepan qué clave usar en la autenticación.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-9-1024x149.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-9-1024x149.png" width="600" height="400" loading="lazy"></figure><p>Copia toda esta clave, incluida la parte ssh-rsa.</p><p>Haz clic en "Nueva clave SSH":</p><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-10.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-10.png" width="600" height="400" loading="lazy"></figure><p>Pega la clave en el cuadro de texto que aparece después de hacer clic en el botón y deberías ver tu clave SSH.</p><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-11.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-11.png" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-conectarse-al-servidor"><strong>Cómo conectarse al servidor</strong></h2><p>Usaremos la terminal para conectarnos a nuestro servidor con SSH. Si quieres también puedes echar un vistazo a Termius para obtener una buena interfaz.</p><p>Ejecuta este comando en tu terminal después de reemplazar IP_ADDRESS con la dirección IP de tu servidor (puedes buscarla desde el panel de Digital Ocean).</p><pre><code>ssh root@IP_ADDRESS</code></pre><p>Si todo va bien, ahora deberías estar en la terminal del servidor. Nos hemos conectado con éxito al servidor. Si hay algún error, puedes depurarlo ejecutando el comando con la opción "-v" o "-vv" para obtener aún más detalle.</p><h2 id="c-mo-configurar-el-servidor"><strong>Cómo configurar el servidor</strong></h2><p>Necesitamos hacer una configuración inicial antes de implementar la aplicación Node en el servidor.</p><h3 id="actualizar-el-software"><strong>Actualizar el software</strong></h3><p>Queremos actualizar el software del servidor para asegurarnos de que estamos usando las últimas versiones.</p><p>Muchos servidores son vulnerables a los ataques porque utilizan versiones anteriores de software con vulnerabilidades conocidas. Los atacantes pueden buscar las vulnerabilidades en ese software e intentar explotarlas para obtener acceso a tu servidor.</p><p>Puedes actualizar el software de Ubuntu usando el comando <strong><strong>"apt update"</strong></strong> .</p><pre><code>apt updateHit:1 https://repos.insights.digitalocean.com/apt/do-agent main InReleaseGet:2 http://mirrors.digitalocean.com/ubuntu focal InRelease [265 kB]      Hit:3 http://mirrors.digitalocean.com/ubuntu focal-updates InRelease                Get:4 http://security.ubuntu.com/ubuntu focal-security InRelease [109 kB]Hit:5 http://mirrors.digitalocean.com/ubuntu focal-backports InReleaseFetched 374 kB in 1s (662 kB/s)                          Reading package lists... DoneBuilding dependency tree       Reading state information... Done96 packages can be upgraded. Run 'apt list --upgradable' to see them.</code></pre><p>Si lees el mensaje, dice que "se pueden actualizar 96 paquetes". Hemos instalado los nuevos paquetes de software, pero aún no hemos actualizado nuestro software a esas versiones.</p><p>Para hacer eso, ejecutemos otro comando:</p><pre><code>apt upgrade</code></pre><p>Escribe 'y' cuando se te solicite y actualizarás el software.</p><h3 id="crear-un-usuario"><strong>Crear un usuario</strong></h3><p>Nos hemos conectado al servidor como el usuario root (el usuario con mayores privilegios). Ser root es peligroso y puede exponernos a vulnerabilidades.</p><p>Por lo tanto, debemos crear un nuevo usuario y no ejecutar comandos como root. Reemplaza <code>$username</code>con un nombre de usuario de tu elección.</p><pre><code>whoamiroot</code></pre><pre><code>adduser $username</code></pre><p>Es necesario introducir una contraseña para el usuario. Después de ese punto, hará un montón de preguntas, así que sigue avanzando hasta que terminen las indicaciones.</p><p>Se ha creado el nuevo usuario, pero también debemos agregar este nuevo usuario al grupo "sudo" para que podamos realizar cualquier acción que necesitemos.</p><pre><code>usermod -aG sudo $USERNAME</code></pre><p>Agregamos grupo con la opción <code>-aG</code> (agregar grupo), y agregamos el nombre del grupo <code>sudo</code>a nuestro nombre de usuario.</p><p>Todavía somos root, así que cambiemos nuestro usuario al usuario recién creado, usando el comando <code>su</code> (cambiar de usuario).</p><pre><code>su $USERNAME</code></pre><p>Después de este punto, si ejecutas el comando <strong><strong><code>whoami</code></strong></strong>, deberías ver tu nombre de usuario. Puedes confirmar la existencia del grupo sudo ejecutando este comando:</p><pre><code>sudo cat /var/log/auth.log</code></pre><p>Solo los superusuarios pueden ver este archivo y el sistema operativo te pedirá tu contraseña de usuario después de ejecutar este comando.</p><h3 id="copia-la-clave-ssh"><strong>Copia la clave SSH</strong></h3><p>Hemos creado correctamente el usuario, pero aún no hemos habilitado el inicio de sesión SSH para este nuevo usuario.</p><p>Por lo tanto, tenemos que copiar la clave pública que creamos previamente en nuestro ordenador local y pegarla en la carpeta SSH de este usuario para que SSH pueda saber qué clave debe usar para autenticar a nuestro nuevo usuario.</p><pre><code>mkdir -p ~/.ssh</code></pre><p>El argumento <code>-p</code> crea el directorio si no existe.</p><pre><code>vi ~/.ssh/authorized_keys</code></pre><p>Usaremos vi o vim para crear un archivo y llamarlo <strong><strong><code>authorized_keys</code></strong></strong>.</p><p>Copia tu clave pública (archivo `id_dsa`) y luego presiona "i" para entrar en el modo de inserción. Luego simplemente pégalo en este archivo con CMD + V (En Mac, si usas PC -&gt; CTRL + V).</p><p>Presiona esc para salir del modo de inserción, escribe <strong><strong>:wq</strong></strong> para guardar y salir.</p><p>Si tienes algún problema con el uso de Vim-Vi, puedes consultar <a href="https://www.freecodecamp.org/news/how-not-to-be-afraid-of-vim-anymore-ec0b7264b0ae/">uno de los muchos tutoriales</a> que explican cómo usarlo.</p><h3 id="conectarse-al-servidor-con-el-nuevo-usuario"><strong>Conectarse al servidor con el nuevo usuario</strong></h3><p>Ahora deberíamos poder conectarnos al servidor sin ningún problema usando ssh. Puedes usar este comando para conectarte, solo recuerda insertar tu nombre de usuario ($USERNAME) y dirección ip (<code>IP_ADDRESS</code>).</p><pre><code>ssh $USERNAME@IP_ADDRESS</code></pre><p>Si tienes algún problema en este punto, simplemente debes eliminar el droplet y comenzar de nuevo. No toma mucho tiempo comenzar de nuevo, pero la depuración de problemas del servidor puede ser difícil.</p><h3 id="c-mo-deshabilitar-el-inicio-de-sesi-n-con-root"><strong>Cómo deshabilitar el inicio de sesión con root</strong></h3><p>Es una buena práctica deshabilitar el inicio de sesión de root como medida de seguridad, así que hagámoslo ahora.</p><p>Puede ser útil cambiar el permiso del archivo por si acaso para que no tengamos problemas con los permisos en el futuro.</p><pre><code>chmod 644 ~/.ssh/authorized_keys</code></pre><p>Ahora abramos nuestro archivo <code>sshd_config</code>:</p><pre><code>sudo vi /etc/ssh/sshd_config</code></pre><p>Encuentra esta línea y cambia el sí por el no de la misma manera que lo hicimos antes con vi.</p><pre><code>PermitRootLogin no</code></pre><p>Guardar y salir de vi.</p><h2 id="c-mo-instalar-node-js-y-git"><strong>Cómo instalar Node.js y Git</strong></h2><p>Ya podemos continuar e instalar Node.js y Git:</p><pre><code>sudo apt install nodejs npm</code></pre><pre><code>sudo apt install git</code></pre><p>Ahora estamos listos para crear una aplicación Node y ejecutarla. Puedes extraer tu proyecto de Node de Github o crear una aplicación de Node aquí para probar si funciona.</p><p>Ves a un directorio de tu elección y crea un archivo <strong><strong>"app.js"</strong></strong> :</p><pre><code>sudo vi app.js</code></pre><p>Puedes pegar el siguiente fragmento en tu archivo <strong><strong>app.js</strong></strong> :</p><pre><code>const express = require('express');const app = express();const port = 3000;app.get('/', (req, res) =&gt; {        res.send('Hola Mundo');});app.listen(port, () =&gt; console.log(`¡Aplicación de ejemplo escuchando en el puerto ${port}!`));</code></pre><p>Ahora podemos ejecutarlo con el comando:</p><pre><code>node app.js</code></pre><p>Deberías ver "¡Aplicación de ejemplo escuchando en el puerto 3000!" en tu terminal.</p><p>Podemos confirmar que está funcionando enviando una solicitud a nuestro servidor:</p><pre><code>GET http://IP_ADDRESS:3000/</code></pre><p>Envía esta solicitud desde un cliente HTTP como Postman o tu navegador y deberías ver el mensaje "Hola Mundo".</p><p>En este punto, deberías notar que algo no está bien: Los usuarios regulares no saben cómo enviar solicitudes al puerto 3000.</p><p>Deberíamos redirigir las solicitudes que llegan a nuestro servidor web desde nuestra IP al puerto 3000. Esto lo podemos lograr con la ayuda de Nginx.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-16.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-16.png" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-instalar-y-configurar-nginx"><strong>Cómo instalar y configurar Nginx</strong></h2><p>Usaremos Nginx como proxy inverso para redirigir las solicitudes a nuestra aplicación Node.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-14-1024x531.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-14-1024x531.png" width="600" height="400" loading="lazy"><figcaption>Nginx como proxy inverso</figcaption></figure><p>Instalamos Nginx:</p><pre><code>sudo apt install nginx</code></pre><p>Inicia el servicio Nginx:</p><pre><code>sudo service nginx start</code></pre><p>Podemos probar para ver si funciona enviando una solicitud a la dirección IP de nuestro servidor desde el navegador. Escribe la dirección IP de tu servidor en tu navegador y deberías ver esto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-15-1024x231.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-15-1024x231.png" width="600" height="400" loading="lazy"></figure><p>Es importante saber que Nginx sirve desde <strong><strong>"/var/www/html"</strong></strong> de forma predeterminada y también puedes encontrar este archivo HTML en ese directorio.</p><p>También te aconsejo que crees una carpeta en "/var/www", llámala app y mueve tu aplicación Node a esa carpeta para que sea fácil de encontrar.</p><h3 id="c-mo-configurar-el-proxy-inverso-de-nginx"><strong>Cómo configurar el proxy inverso de Nginx</strong></h3><p>Editaremos el archivo de configuración de Nginx para configurar un proxy inverso:</p><pre><code>sudo vi /etc/nginx/sites-available/default</code></pre><p>En este archivo, debes encontrar la ubicación / block y cambiarla de la siguiente manera:</p><pre><code>location / {                # First attempt to serve request as file, then                # as directory, then fall back to displaying a 404.                proxy_pass http://127.0.0.1:3000/;        }</code></pre><p>La directiva<code>proxy_pass</code> envía la solicitud a un puerto específico. Damos el puerto en el que se ejecuta nuestra aplicación Node.</p><p>Reiniciamos Nginx para que los cambios surtan efecto:</p><pre><code>sudo service nginx reload</code></pre><p>Después de este paso, deberíamos poder ver el mensaje cuando enviamos una solicitud a nuestro servidor. ¡Felicidades, hemos completado la cantidad mínima de pasos para implementar una aplicación Node!</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-24-at-01.10.33-1024x67.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-24-at-01.10.33-1024x67.png" width="600" height="400" loading="lazy"></figure><p>Pero aún así te aconsejo que completes el siguiente paso también, ya que creo que es bastante importante.</p><p>Si no puedes ver el mensaje de hola mundo, puedes verificar si tu aplicación y Nginx se están ejecutando y reiniciarlos.</p><h2 id="c-mo-ejecutar-tu-aplicaci-n-como-un-proceso"><strong>Cómo ejecutar tu aplicación como un proceso</strong></h2><p>No queremos iniciar nuestra aplicación manualmente cada vez que algo salga mal y nuestra aplicación falle. Queremos que se reinicie solo. Además, cada vez que se inicia el servidor, nuestra aplicación también debería iniciarse.</p><p>Para que esto suceda, podemos usar PM2. Instalemos PM2 y configuremos.</p><pre><code>sudo npm i -g pm2</code></pre><p>Estamos instalando pm2 globalmente usando la opción "-g" para que sea accesible desde todas las carpetas.</p><pre><code>pm2 start app.js</code></pre><p>Esto asegura que la aplicación se reinicie si se cierra debido a un error.</p><p>Guardemos la lista de procesos actual.</p><pre><code>pm2 save</code></pre><p>También necesitamos convertirlo en un demonio que se ejecute cada vez que se inicie el sistema:</p><pre><code>pm2 startup systemd</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-17.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-17.png" width="600" height="400" loading="lazy"></figure><p>Como recordatorio, en este tutorial estoy usando los comandos para Ubuntu. Si estás utilizando cualquier otra distribución de Linux, debes reemplazar <code>systemd</code> en este comando.</p><p>Podemos confirmar que el servicio se reinicia reiniciando el servidor y enviando una solicitud sin ejecutar app.js a mano:</p><pre><code>sudo reboot</code></pre><p>Después de enviar una solicitud como lo hicimos anteriormente, deberías poder ver el mensaje de hola mundo.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>En este tutorial, comenzamos desde cero, alquilamos un servidor, nos conectamos y lo configuramos de manera que sirve nuestra aplicación Node.js desde el puerto 80.</p><p>Si has seguido y has podido completar todos los pasos, ¡felicidades! Puedes estar orgulloso de ti mismo, ya que este tema no es de lo más fácil :). Espero que hayas aprendido mucho. Gracias por tu tiempo.</p><p>Planeo explorar más este tema conectando el servidor a un nombre de dominio y luego conectándolo a CircleCI para una integración continua. También revisaré los pasos necesarios para preparar la producción de tu aplicación Node.js/React. Sin embargo, esta publicación ya se había hecho lo suficientemente larga, por lo que esos temas están reservados para otra publicación :)</p><p>Si te ha gustado la lectura y quieres estar informado de mis futuras publicaciones, puedes suscribirte a mi <a href="https://erinc.io/">blog personal</a> . Puedes ver mis publicaciones anteriores allí si estás interesado en leer más. Suelo escribir sobre temas relacionados con el desarrollo web.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Aprende Node.js y Express - Curso desde cero ]]>
                </title>
                <description>
                    <![CDATA[ ¡Hola! Si quieres aprender Node.js y Express, estás en el lugar correcto. En este artículo encontrarás una breve introducción al desarrollo web back-end, Node.js y Express. Aprenderás por qué son herramientas muy poderosas para desarrollar servidores y por qué deberías aprenderlos si tu meta es adentrarte en el mundo del ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/aprende-node-js-y-express-curso-desde-cero/</link>
                <guid isPermaLink="false">62d1b64fb4def50851972da5</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Estefania Cassingena Navone ]]>
                </dc:creator>
                <pubDate>Sun, 07 Aug 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/07/thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>¡Hola! Si quieres aprender Node.js y Express, estás en el lugar correcto.</p><p>En este artículo encontrarás una breve introducción al desarrollo web back-end, Node.js y Express. Aprenderás por qué son herramientas muy poderosas para desarrollar servidores y por qué deberías aprenderlos si tu meta es adentrarte en el mundo del desarrollo web back-end. </p><p>Luego, encontrarás un <a href="https://www.youtube.com/watch?v=1hpc70_OoAg">curso de <strong>8.5</strong> <strong>horas </strong>de Node.js y Express</a> en el canal de YouTube de freeCodeCamp en español donde puedes aprender los fundamentos en español y construir un proyecto paso a paso. </p><p>¡Comencemos! ✨</p><h2 id="-qu-es-el-desarrollo-web-back-end">🔸<strong> ¿Qué es el desarrollo web back-end? </strong></h2><p>El desarrollo web ha transformado nuestro mundo. Cada día accedemos a internet para encontrar información, aprender, comprar productos, compartir opiniones y comunicarnos con familiares y amigos. </p><p>Básicamente, nuestras vidas no serían lo mismo sin los sitios web. </p><p>¿Estás de acuerdo? 🙂</p><p>Si estás de acuerdo, entonces aprendiendo desarrollo web puedes desarrollarte en una carrera muy gratificante y puedes impactar las vidas de miles o millones de usuarios desarrollando aplicaciones web. </p><p>Hablemos sobre las distintas áreas del desarrollo web. </p><h3 id="desarrollo-web-front-end-vs-desarrollo-web-back-end">Desarrollo web front-end vs. desarrollo web back-end</h3><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-7.png" class="kg-image" alt="image-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/07/image-7.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2022/07/image-7.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-7.png 1920w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"></figure><p>Los desarrolladores que crean estas aplicaciones web asombrosas son llamados <strong>desarrolladores web</strong>. Pueden especializarse para desarrollar partes específicas de una aplicación web:</p><ul><li>Los <strong>desarrolladores web front-end</strong> implementan la parte de la aplicación web con la cual los usuarios interactúan directamente. Crean la parte visible de las plataformas asombrosas que usamos cada día. En la analogía de la tienda que puedes ver en la imagen anterior, el front-end estaría representado por la parte de la tienda que los clientes pueden ver.</li><li>Los <strong>desarrolladores web back-end</strong> implementan toda la funcionalidad que los usuarios no ven, tales como los servidores, bases de datos y todas sus interacciones con el front-end de la aplicación. </li><li>Los <strong>desarrolladores web full-stack </strong>se encargan de ambas áreas. Tienen conocimiento extenso sobre desarrollo web front-end y back-end. </li></ul><p>Interesante, ¿cierto? ✨</p><p>Veamos más detalles sobre el desarrollo web back-end porque esta es una de las principales aplicaciones de Node.js y Express. </p><h3 id="el-modelo-cliente-servidor">El modelo cliente-servidor</h3><p>El internet está basado en el modelo o la arquitectura cliente-servidor, en la cual dos dispositivos (el cliente y el servidor) se comunican entre sí. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-173.png" class="kg-image" alt="image-173" width="600" height="400" loading="lazy"><figcaption>Diagrama del modelo cliente-servidor. Cliente (izquierda). Servidor (derecha).</figcaption></figure><h3 id="el-cliente">El cliente</h3><p>Cuando intentas acceder a una página web en tu navegador, el navegador (<strong>cliente</strong>) envía una solicitud HTTP al servidor. </p><h3 id="el-servidor">El servidor</h3><p>El <strong>servidor </strong>es un programa que escucha solicitudes y genera respuestas apropiadas. Estas respuestas incluyen:</p><ul><li>Enviar información al cliente. </li><li>Ejecutar tareas o procesos.</li><li>Trabajar con la información de una base de datos y/o actualizarla. </li></ul><p>Por ejemplo, podemos agregar un usuario nuevo a una base de datos al enviar una solicitud al servidor y el servidor debe realizar las actualizaciones correspondientes en la base de datos. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-175.png" class="kg-image" alt="image-175" width="600" height="400" loading="lazy"><figcaption>Cliente (izquierda) - Servidor (centro) - Base de datos (derecha)</figcaption></figure><p>Desarrollar y mantener servidores es una de las tareas principales de los desarrolladores back-end y esa es precisamente la función principal de <strong>Node.js y Express</strong>. </p><h2 id="-qu-es-node-js"><strong>🔹</strong> ¿Qué es Node.js? </h2><p><strong>Node.js</strong> es un runtime de JavaScript asíncrono y basado en eventos desarrollado en base al motor V8 de JavaScript de Chrome. Nos da todas las herramientas que necesitamos para ejecutar JavaScript en el terminal sin un navegador web (browser). </p><p>💡<strong> Dato:</strong> Antes de Node.js, no podíamos ejecutar programas de JavaScript sin un navegador web. Solo los navegadores habían sido diseñados para esta tarea ya que JavaScript es uno de los principales lenguajes de programación de la web. </p><p>Lo asombroso de Node.js es que nos permite construir aplicaciones escalables con alto rendimiento. </p><p>De acuerdo a su <a href="https://nodejs.org/es/about/">documentación oficial</a>:</p><blockquote>Los usuarios de Node.js están libres de preocuparse por el bloqueo del proceso, ya que no existe. Casi ninguna función en Node.js realiza I/O directamente, por lo que el proceso nunca se bloquea. Por ello, <strong>es muy propicio desarrollar sistemas escalables en Node.js.</strong></blockquote><p>🚩 Es importante resaltar que <strong>Node.js no es</strong> un: </p><ul><li>Lenguaje de programación.</li><li>Framework.</li><li>Librería (biblioteca).</li></ul><p>Es un <strong>runtime de JavaScript</strong> desarrollado para ejecutar código de JavaScript. </p><h3 id="-por-qu-deber-as-aprender-node-js"><strong>¿Por qué deberías aprender Node.js?</strong></h3><p>Ahora que ya sabes más sobre Node.js, veamos por qué deberías aprenderlo. </p><p><strong>Node.js </strong>es una de las tecnologías web más populares entre los desarrolladores, incluyendo principiantes que están aprendiendo a programar y profesionales. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/node-logo.png" class="kg-image" alt="node-logo" width="600" height="400" loading="lazy"><figcaption>Logo de Node.js</figcaption></figure><p>La popularidad de Node.js es asombrosa. De acuerdo a la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>, es una de las tecnologías web más populares usadas por los que están aprendiendo a programar y por desarrolladores profesionales.</p><p>Cuando a los encuestados se les preguntó cuáles frameworks web o tecnologías web habían usado constantemente el año pasado y con cuáles querían trabajar el próximo año, <strong>Node.js</strong> obtuvo un <strong>47.12%</strong> de los votos. </p><p>💡<strong> Dato:</strong> ¡casi la mitad de las 58,743 respuestas!</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-8.png" class="kg-image" alt="image-8" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-8.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-8.png 922w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría de Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>. <strong>Node.js es el primero con 47.12% de las respuestas.</strong></figcaption></figure><p>Ese porcentaje fue incluso mayor entre los encuestados que estaban aprendiendo a programar: &nbsp;<strong>52.86%</strong>. Asombroso, ¿verdad? 😁</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-9.png" class="kg-image" alt="image-9" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-9.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-9.png 919w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría de Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a> cuando se selecciona Learning to Code. <strong>Node.js es el primero con 52.86% de las respuestas.</strong></figcaption></figure><p>Esto demuestra el impacto que Node.js está teniendo en el área del desarrollo web. Al aprender Node.js estarás invirtiendo tu tiempo y recursos sabiamente. Adquirirás habilidades valiosas y altamente demandadas en este campo. </p><h2 id="-qu-es-express"><strong>🔸</strong> ¿Qué es Express? </h2><p>Si tu meta es desarrollar servidores con Node.js, el proceso puede ser mucho más fácil si usas <strong>Express</strong>, un framework de aplicaciones web específicamente diseñado para Node.js. </p><p>Según la <a href="https://expressjs.com/">documentación oficial</a> de Express:</p><blockquote>Express es un framework de aplicaciones web de Node.js mínimo y flexible que provee un conjunto robusto de herramientas para aplicaciones web y móviles. </blockquote><p>Original en inglés:</p><blockquote>Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.</blockquote><p>💡<strong> Dato:</strong> Express incluye muchas herramientas que puedes usar para escribir código más conciso, fácil de leer y fácil de mantener. Confía en mi. Cuando comiences a trabajar con Express, nunca querrás dejarlo. </p><p>Express tiene muchos métodos HTTP útiles y middleware que puedes usar para crear APIs robustas (Application Programming Interfaces), las cuales son fundamentales para el desarrollo web back-end y full-stack. </p><p>En la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>, Express fue la cuarta tecnología o framework web más usado con <strong>22.99%</strong> de los votos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-10.png" class="kg-image" alt="image-10" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-10.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-10.png 938w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer</a> Survey</figcaption></figure><p><strong>¡Genial! </strong>Ya sabes por qué deberías aprender Node.js y Express. Te prometo que de verdad merecerá tu tiempo y dedicación. ✨</p><h2 id="-contenido-del-curso">🔹<strong> Contenido del curso</strong></h2><p>Ahora veamos lo que aprenderás durante el curso.</p><p>💡<strong><strong> </strong>Dato<strong>:</strong></strong> para tomar el curso, debes tener conocimiento previo de <strong>JavaScript</strong>. Si necesitas repasar este lenguaje de programación en español, te recomiendo tomar el <a href="https://www.youtube.com/watch?v=ivdTnPl1ND0&amp;t=3s">curso de JavaScript</a> en el canal de YouTube de freeCodeCamp en español.</p><h3 id="introducci-n-a-node-js-y-conceptos-b-sicos">Introducción a Node.js y conceptos básicos</h3><ul><li>Introducción a Node.js</li><li>Conceptos básicos de desarrollo web back-end. </li><li>Aplicaciones de Node.js</li><li>APIs y para qué se usan. </li><li>Ventajas de Node.js.</li><li>Descargar e instalar Node.js.</li><li>Confirmar que Node.js fue instalado exitosamente. </li><li>Verificar tu versión de Node.js.</li><li>El REPL de Node.js.</li></ul><h3 id="tu-primer-proyecto-de-node-js-y-m-dulos">Tu primer proyecto de Node.js y módulos</h3><ul><li>¿Qué es un módulo? Conceptos y ventajas.</li><li>Exportar e importar módulos.</li><li>Exportar varios elementos de un módulo de JavaScript.</li><li>Ejecutar un archivo JavaScript con el comando <code>node</code>.</li><li>Módulos core de Node.js.</li><li>El módulo <code>console</code>.</li><li>El módulo <code>process</code>.</li><li>El módulo <code>os</code>.</li><li>El módulo <code>fs</code>.</li><li>El módulo <code>timers</code>.</li></ul><h3 id="introducci-n-a-npm-y-json">Introducción a npm y JSON</h3><ul><li>¿Qué es npm?</li><li>Conceptos básicos de npm.</li><li>Inicializar un paquete con <code>npm init</code>.</li><li>El archivo <code>package.json</code>.</li><li>Introducción al formato JSON.</li><li>Instalar y desinstalar paquetes con npm.</li><li>El archivo <code>package-lock.json</code>.</li></ul><h3 id="eventos-y-operaciones-as-ncronas">Eventos y operaciones asíncronas</h3><ul><li>¿Qué es un evento?</li><li>Eventos en Node.js.</li><li>Eventos y procesos síncronos y asíncronos. </li><li>Promesas y funciones callback en JavaScript. </li><li>Promesas, <code>.then()</code> y <code>.catch()</code>.</li><li>Funciones asíncronas con <code>async</code> y <code>await</code>.</li></ul><h3 id="servidores-con-node-js-y-el-protocolo-http">Servidores con Node.js y el protocolo HTTP</h3><ul><li>El modelo cliente-servidor.</li><li>Formato de solicitudes y respuestas HTTP.</li><li>Métodos o verbos HTTP: &nbsp;GET, POST, PUT, DELETE.</li><li>Códigos de estado HTTP.</li><li>El módulo <code>http</code> en Node.js.</li><li>Crear un servidor en Node.js.</li><li>Los objetos <code>req</code> y <code>res</code>.</li><li>Estructura de una URL. </li><li>Routing (Enrutamiento) en Node.js. </li></ul><h3 id="nodemon">Nodemon</h3><ul><li>¿Qué es Nodemon?</li><li>Cómo instalarlo globalmente.</li><li>Cómo usarlo para actualizar aplicaciones de Node.js automáticamente.</li><li>Conceptos importantes: CRUD, REST, API.</li></ul><h3 id="express">Express</h3><ul><li>Cómo instalar Express y cómo crear un proyecto.</li><li>Routing en Express.</li><li>Express y Nodemon. </li><li>Cómo manejar varias rutas.</li><li>Parámetros de URL y rutas dinámicas. </li><li>Middleware en Express. </li><li>Manejar solicitudes GET, POST, PUT y DELETE.</li><li>Parámetros query. </li><li>Routers en Express. </li></ul><h2 id="-proyecto-de-node-js-y-express">🔸<strong> Proyecto de Node.js y Express</strong></h2><p>Durante el curso aprenderás con ejemplos prácticos, así que aplicarás todo lo que aprendas paso a paso. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/08/image-3.png" class="kg-image" alt="image-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/08/image-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/08/image-3.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2022/08/image-3.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2022/08/image-3.png 1920w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"><figcaption>Proyecto que crearemos con Node.js y Express</figcaption></figure><p>Aprenderás cómo trabajar con promesas con un ejemplo de pizza 🍕, cómo trabajar con JavaScript asíncrono, y desarrollarás una API y un servidor básico con Node.js para enviar información sobre cursos de programación y matemáticas al cliente. </p><p>Luego, adaptarás este servidor para trabajar con Express. Aplicarás conceptos que has aprendido y aprenderás nuevos conceptos paso a paso para crear un servidor que manejará varias rutas, parámetros y distintos tipos de solicitudes HTTP.</p><h2 id="-curso-de-node-js-y-express-en-youtube"><strong>📌</strong> Curso de Node.js y Express en YouTube</h2><p>Genial. Ahora que ya sabes más sobre Node.js y Express y lo que aprenderás durante el curso, te invito a tomar el curso completo en español:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/1hpc70_OoAg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende Node.js y Express - Curso desde Cero" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>✍️ Curso creado por Estefania Cassingena Navone (Twitter: <a href="https://twitter.com/EstefaniaCassN">@EstefaniaCassN</a>, YouTube: <a href="https://www.youtube.com/codingwithestefania">Coding with Estefania</a>).</p><p>Sinceramente espero que te guste el curso y que te ayude a tomar tus primeros pasos en el mundo de Node.js, Express y desarrollo web back-end. </p><p>También te invitamos a tomar nuestros cursos de programación en <strong>español</strong>:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/XqFR2lqBYPs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende HTML y CSS - Curso Desde Cero" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/ivdTnPl1ND0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende JavaScript - Curso Completo desde Cero" name="fitvid2"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/DLikpfc64cA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Introducción a Programación en Python" name="fitvid3"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/6Jfk8ic3KVk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende React Desde Cero - Curso de React Con Proyectos" name="fitvid4"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
