Servidores y bases de datos con Node.js
En el artículo anterior hablamos del desarrollo web y cómo funcionan las páginas que utilizan la arquitectura cliente-servidor. A partir de este artículo comenzaremos a indagar en la parte del Backend, enfocada en la creación del servidor y en el manejo de base de datos.
Para la creación de este servidor utilizaremos Node.js y más adelante implementaremos MongoDB como base de datos.
Pero antes de empezar con el proyecto, donde crearemos un servidor profesional, me gustaría introducirles varios conceptos de Node.js. Les recomiendo visitar el siguiente link que los llevará un articulo de un colega donde hace una introducción a Node.js en un sentido de rendimiento, instalaciones, entre otros.
¿Cómo correr JavaScript fuera del navegador?
Como sabemos, nosotros podemos escribir código JavaScript en un navegador simplemente yendo a la consola, pero gracias a Node podríamos ejecutar JavaScript sin la necesidad de un navegador.
A continuación, para mostrar cómo hacerlo, usaré Visual Studio Code, un IDE (Integrated Development Environment) muy utilizado para el desarrollo en JavaScript y es el que usaremos para el resto del curso. Aquí podrás descargar VScode.
Sigamos estos pasos:
1- Vamos a VScode y abrimos su terminal con command + j en Mac o Ctrl + Shift + `, podríamos usar cualquier terminal, pero para evitar cambiar muchas veces de ventanas, usaremos la integrada de VScode.
2- Ingresamos el comando node, el cual nos abrirá node REPL (Read Eval Print Loop), una herramienta de línea de comandos que captura las entradas del código JavaScript, lo interpreta y evalúa el resultado del código.
3- Si oprimimos 2 veces Tab, nos aparecerá una lista de funcionalidades válidas para usar en la node REPL. Para salir de ésta ingresamos el comando .exit.
Módulos en Node
Para ahondar en temas de Node, nos introduciremos ahora en los módulos. Un módulo en Node es solo un archivo JavaScript que contiene código relacionado. En JavaScript, usamos las palabras clave de importación y exportación para compartir y recibir funcionalidades respectivamente a través de diferentes módulos. La palabra clave export se utiliza para hacer que una variable, función, clase u objeto sea accesible para otros módulos.
Tenemos 3 tipos de módulos: Core Modules, Local Modules y Third Party Modules.
1- Core modules
Los Core Modules o módulos principales incluyen funcionalidades mínimas de Node.js. Estos se compilan en su distribución binaria y se cargan automáticamente cuando se inicia el proceso de Node.js. Sin embargo, primero se debe importar el módulo en el archivo donde lo queramos implementar para así usarlo en nuestra aplicación.
Algunos de los módulos más importantes
http -> Ele inclui classes, métodos e eventos para criar um servidor http no Node.js.
url -> Incluye métodos para la resolución y el análisis de URL.
querystring -> Incluye métodos para tratar con la cadena de consulta (query string).
path -> Incluye métodos para tratar con rutas de archivo (path).
fs -> Incluye clases, métodos y eventos para trabajar con archivos de Input/Output.
util -> Incluye funciones de utilidad útiles para los programadores.
2- Local modules
Los módulos locales son aquéllos creados localmente en tu aplicación Node.js. Estos módulos incluyen diferentes funcionalidades de tu aplicación en archivos y carpetas separados. También puedes empaquetarlo y distribuirlo a través de NPM, para que la comunidad de Node.js pueda usarlo. Por ejemplo, si necesitas conectarte a MongoDB y obtener datos, puedes crear un módulo para ello que puede reutilizarse en tu aplicación.
3- Third Party Modules
Son módulos disponibles en línea y se instalan mediante npm. También se denominan módulos de terceros. Algunos ejemplos de módulos de terceros son Express, Mongoose, etc.
Core modules y sus usos
En esta parte usaré los conceptos antes mencionados para crear varios casos de uso de los core modules. Estos mismos formarán gran parte de nuestro día a día como desarrolladores Backend.
Aquí abordaremos un ejemplo la lectura y escritura de archivos tal como es, que también podría explicar la naturaleza asíncrona de Node.js. Sin embargo, este no será el único artículo donde encontrarás ejemplos prácticos de core modules, así que... ¡Mantente atento a mis próximos artículos!
La lectura y escritura de archivos, como su nombre bien lo da a entender, se encarga de la obtención del contenido de un archivo de texto, así como también de la creación y escritura del mismo.
Escritura sincrónica
// Aquí requerimos el core module 'fs', este nos permite realizar la
// lectura y escritura de archivos
const fs = require('fs');
// Guardamos en una variable un texto que queramos guardar
let texto = 'Esto es solo un texto de ejemplo';
// Y por último, utilizamos el módulo fs para crear el archivo y guardar
// el texto antes creado
// este archivo lo crearemos con el método 'writeFileSync' el cual por
// primer parámetro guardamos el directorio donde se guardará el
// archivo y como segundo parámetro le pasamos el texto que queremos
// guardar en este
fs.writeFileSync('./escritura.txt', texto);
Para ejecutar este archivo debemos tener nociones básicas del manejo de comandos en la terminal. Si no tienes, ¡no te preocupes!, yo te guiaré para que sepas cómo hacerlo en un futuro. Por el momento haz los siguientes pasos:
- Abre este archivo en VScode.
- Una vez en VScode. abre la terminal con Ctrl + J si usas Windows, o Command + J si usas en Mac.
- Pasa el comando "node <NombreDelArchivo>" (obviamente sin comillas y con el nombre del archivo donde hayas guardado el código).
¡Y listo! Al instante se creará el archivo de texto con lo que hayas guardado.
Lectura Sincrónica
// Requerimos el módulo 'fs' para leer un archivo
const fs = require('fs');
// Luego crearemos una variable donde guardaremos lo que obtengamos de
// la lectura de un archivo de texto utilizando el método
// "readFileSync" el cual toma por primer parámetro debemos pasarlo el
//directorio del archivo que queremos leer, y como segundo parámetro
// pasamos 'utf-8'que es la codificación de caracteres más común de la
//World Wide Web.
const texto = fs.readFileSync('./escritura.txt', 'utf-8');
// Por último podríamos usar esta variable para hacer lo que queramos
// con lo que obtengamos, pero en este caso solo lo mostraremos por
// consola
console.log(texto);
Cuando ejecutemos este código (como hicimos con el anterior), obtendremos por consola lo guardado en el archivo de texto.
Esto funciona muy bien, aunque tiene un problema: todo lo que hicimos fue hecho de forma sincrónica, lo que nos lleva a el próximo tema.
Código de bloqueo y não bloqueio, a naturaleza asíncrona de Node.js
Cuando hablamos de código sincrónico, entendemos que dicho código se ejecuta línea por línea, es decir, hasta que no se termine de ejecutar una acción, no se podrá pasar a otra. Como podrás pensar, esto ocasionará un gran problema de bloqueo del código, el cual haría que el código sea lento. Para resolver este problema, se utiliza código asíncrono.
Para explicarlo mejor, veamos unas imágenes explicativas del caso:
Node.js corre sus aplicaciones en un "hilo único" (single thread) donde todos los usuarios se conectarán. Por lo tanto, es importante no bloquearlo.
Si usamos código síncrónico, bloquearemos este hilo y la aplicación se volvería innecesariamente lenta.
Si usamos código asíncrono, enviaremos las tareas que bloquean nuestro código a un background donde se terminarán de ejecutar y, una vez resueltas, se devolverá el resultado al hilo principal.
Para lograr dicho código asíncrono utilizamos las callbacks functions. Por más que esto solucionaría el problema, no significa que las callbacks sean código asíncrono ni sean la mejor solución, ya que existen más alternativas como las promesas y async/await functions, conceptos que repasaremos más adelante.
Leyendo y escribiendo archivos de forma asíncrona
Escritura asincrónica
// Requerimos el módulo 'fs'
const fs = require('fs');
// Este mismo módulo nos permite usar métodos asíncronos, en este caso
// 'writeFile' toma los mismos parámetros que 'writeFileSync', pero con
// la diferencia que como tercer parámetro le pasamos una callback
// function
fs.writeFile('./escrituraAsync.txt', `algo que queramos guardar`, err => {
console.log("Tu archivo ha sido creado!");
});
Lectura asincrónica
const fs = require('fs');
// Este método toma los mismos parámetros que el 'readFileSync' pero como
// tercer parámetro toma una callback function, cuyos parámetros son
// primero donde se guardaría el error en caso de algo salga mal, y como
// segundo parámetro lo que se obtuvo de dicha lectura
fs.readFile('./escrituraAsync.txt', 'utf-8', (err,data) => {
console.log(data);
})
Lectura y escritura asincrónica
const fs = require('fs');
// Primero leemos un archivo y guardamos su contenido en la callback
// function
fs.readFile('./escrituraAsync.txt', 'utf-8', (err,data1) => {
// Luego hacemos una escritura a un archivo usando lo guardado
// anteriormente para poder guardarlo nuevamente en otro archivo, y
// tambien agregandole unas cosas más
fs.writeFile('./final.txt', `${data1}\\nY eso seria todo!`, err => {
console.log("Su archivo se creo de forma correcta!");
});
});
De esta manera, se pueden usar la escritura y lectura de archivos para una amplia variedad de actividades.
Por aquí dejaré el repositorio de GitHub donde encontrarás todos los códigos utilizados en este artículo y en los artículos venideros.
¡Y eso es todo ! En mi próximo escrito emplearé algunos core modules para la creación de un servidor simple y enrutado, así como mucho más.
¡Saludos!
Revelo Content Network da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.