En el siguiente post les enseño los pasos para crear un proyecto esqueleto con CRUD de un modelo conectado a MongoDB. No introduciré demasiado en cómo funciona NodeJS como tal, existen varias páginas que ayudan en este aspecto. La motivación es porque la generación automática de CRUD de un modelo en NodeJS no es tan intuitivo para nuevos usuarios en esta plataforma.
Las siguientes semanas haré un post con un proyecto más avanzado. Todo el código de esta entrada pueden encontrarla en: https://github.com/arturoverbel/nodejs_skeleton.
¿Qué es NodeJS?
Es un entorno de servidor de código abierto que corre el lenguaje de Javascript. Es gratis, corre en varias plataformas como Windows, Linux, Mac, etc.
A diferencia de otros servidores, NodeJS utiliza programación asincrónica. Esto quiere decir que cuando a NodeJS le llega una solicitud, esta pueda ir procesando (buscar el archivo, leerlo y devolverla al cliente), mientra espera otras solicitudes. Otros servidores como los de PHP y ASP esperan hasta que la solicitud termine para estar disponible para otra solicitud.
Al usar el mismo lenguaje en el cliente como en el servidor, se utiliza el mismo paradigma. NodeJS es una programación orienta a eventos. Lo que ha resultado muy fácil para aplicaciones escalables.
NPM
Traduce (Node Package Manager) y es el gestor de paquete de Javascript para NodeJS. Gracias a este programa tenemos acceso a todas las librerías a un comando de distancia. La instalación puede ser de manera global en el computador, o local en la carpeta del proyecto NodeJS. También nos ayuda administrar la información de nuestra aplicación.
Instalación
Las siguientes instrucciones son para instalar NodeJS en Linux.
$ cd /tmp $ wget http://nodejs.org/dist/v6.3.1/node-v6.3.1-linux-x64.tar.gz $ tar xvfz node-v6.3.1-linux-x64.tar.gz $ mkdir -p /usr/local/nodejs $ mv node-v6.3.1-linux-x64/* /usr/local/nodejs $ export PATH=$PATH:/usr/local/nodejs/bin
En este punto podemos escribir en la consola node y que nos aparezca el terminal REPL, el cual es un entorno para ingresar comando y arrojar resultados. Así como la consola de Windows, o el shell de linux.
$ node >
Desde aquí se pueden realizar varias tareas, ciclos y hasta consultas a la base de datos con el lenguaje Javascript ( Vaya poder ). También podemos ejecutar un script de javascript con este comando. Pero en este tutorial haremos caso omiso a todos estos detalles y pasaremos a la instalación de la base de datos y entornos para montar nuestra aplicación web.
Mongo
Pasamos la siguiente linea de comando:
$ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list $ sudo apt-get update $ sudo apt-get install mongodb-10gen = 2.2.3
Así como el servicio de mysql podemos apagar, encender y ver su estado con:
$ sudo service mongodb stop $ sudo service mongodb start $ sudo service mongodb status
Iniciar proyecto
Instamos la librería express de modo global en nuestra máquina.
$ npm install express-generator -g
Luego pasamos el comando:
$ express --view=twig project
Este comando genera una carpeta con todo lo necesario para iniciar nuestro proyecto los cuales son:
- app.js: Es el archivo principal y aquí se inicializa todas las variables y los entornos. También se definen los archivos que interactuan entre ellos.
- /bin/www: Se definen aspectos avanzados de la apliación
- package.json: El archivo donde se define la informació básica del app y las librerías que utiliza. Necesario para un proyecto de NodeJS.
- /public: Carpeta con archivos públicos en la web
- /routes: Carpeta con archivos donde se definen todas las rutas del app
- /views: Carpeta con los archivos de vista
En la vista los archivos son formato TWIG como se definió en el comando anterior. Otros populares son EJS.
Instalamos la librería de mongo para que nuestra app se conecta con nuestra base de datos:
$ npm install mongoose
En este punto podemos ver nuestro proyecto corriendo con:
$ DEBUG=project:* npm start

Imagen 1. Página por defecto de express
Configuración con MongoDB
En app.js se configura la conexión con Mongo
var mongoose = require('mongoose'); var mongoDB = 'mongodb://127.0.0.1:27017/mydb'; //BD mongoose.connect(mongoDB); mongoose.Promise = global.Promise; var db = mongoose.connection; db.on('error', console.error.bind(console, 'MongoDB connection error:'));
Escribir el CRUD
Lo primero es establecer los modelos. Creamos la carpeta /models y escribimos nuestro modelo Product.js:
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var ProductSchema = new Schema({ name: {type: String, required: true, max: 100}, price: {type: Number, required: true}, created_at: { type: Date, default: Date.now } }); module.exports = mongoose.model('Product', ProductSchema);
Para este modelo entonces necesitaremos un controlador para gestionar todas als acciones. Creamos la carpeta /controllers y agregamos el archivo ProductController.js, en este archivo agregaremos todas las acciones que corresponde al modelo Product.
Controlador
Listar
var mongoose = require('mongoose'); var Product = require("../models/Product"); var productController = {}; productController.list = function(req, res){ Product.find({}).exec(function(err, products){ if( err ){ console.log('Error: ', err); return; } console.log("The INDEX"); res.render('../views/product/index', {products: products} ); }); }; /* * Other actions */ module.exports = productController;
Mostrar
productController.show = function(req, res){ Product.findOne({_id: req.params.id}).exec(function(err, product){ if( err ){ console.log('Error: ', err); return; } res.render('../views/product/show', {product: product} ); }); };
Crear
productController.create = function(req, res){ res.render('../views/product/create'); }; productController.save = function(req, res){ var product = new Product( req.body ); product.save(function(err){ if( err ){ console.log('Error: ', err); return; } console.log("Successfully created a product. :)"); res.redirect("/products/show/"+product._id); }); };
Editar
productController.edit = function(req, res) { Product.findOne({_id: req.params.id}).exec(function (err, product) { if (err) { console.log("Error:", err); return; } res.render("../views/product/edit", {product: product}); }); }; productController.update = function(req, res){ Product.findByIdAndUpdate( req.params.id, {$set: { name: req.body.name, price: req.body.price }}, { new: true }, function( err, product){ if( err ){ console.log('Error: ', err); res.render('../views/product/edit', {product: req.body} ); } console.log( product ); res.redirect('/products/show/' + product._id); }); };
Borrar
productController.delete = function(req, res){ Product.remove({_id: req.params.id}, function(err){ if( err ){ console.log('Error: ', err); return; } console.log("Product deleted!"); res.redirect("/products"); }); };
Vistas
Las vistas se realizan en formato TWIG para este ejemplo. Creamos la carpeta /views/product/ dentro de views y agregamos los siguientes archivos:
Crear
<!DOCTYPE html> <html> <head> <title>Create Product</title> </head> <body> <div class="container"> <h3><a href="/products">Product List</a></h3> <h1>Create New Product</h1> <form action="/products/save" method="post"> <table> <tbody> <tr> <td>Name</td> <td><input type="text" name="name" /></td> </tr> <tr> <td>Price</td> <td><input type="text" name="price" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="Save" /></td> </tr> </tbody> </table> </form> </div> </body> </html>

Imagen 2. Crear el modelo
Editar
<!DOCTYPE html> <html> <head> <title>Edit Product</title> </head> <body> <div class="container"> <h3><a href="/products">Product List</a></h3> <h1>Edit Product</h1> <form action="/products/update/{{ product._id }}" method="post"> <table> <tbody> <tr> <td>Name</td> <td><input type="text" name="name" value="{{ product.name }}" /></td> </tr> <tr> <td>Price</td> <td><input type="text" name="price" value="{{ product.price }}" /></td> </tr> <tr> <td colspan="2"><button type="submit">Update</button></td> </tr> </tbody> </table> </form> </div> </body> </html>

Imagen 3. Editar modelo
Listar
<!DOCTYPE html> <html> <head> <title>Product List</title> </head> <body> <div class="container"> <h3><a href="/products/create">Create Product</a></h3> <h1>Product List</h1> {% if products is not empty %} <table> <thead> <tr> <th>ID</th> <th>Employee Name</th> <th>Position</th> </tr> </thead> <tbody> {% for product in products %} <tr> <td><a href="/products/show/{{ product._id }}">{{ product._id }}</a></td> <td><a href="/products/show/{{ product._id }}">{{ product.name }}</a></td> <td>{{ product.price }}</td> </tr> {% endfor %} </tbody> </table> {% else %} <div>No products found.</div> {% endif %} </div> </body> </html>

Imagen 4. Listar modelo
Mostrar
<!DOCTYPE html> <html> <head> <title>Product Detail</title> </head> <body> <div class="container"> <h3><a href="/products">Product List</a></h3> <h1>Product Detail</h1> <table> <tbody> <tr> <td>Name</td> <td>{{ product.name }}</td> </tr> <tr> <td>Address</td> <td>{{ product.price }}</td> </tr> </tbody> </table> <h3><a href="/products/edit/{{ product._id }}">EDIT</a></h3> <form action="/products/delete/{{ product._id }}" method="post"> <button type="submit">DELETE</button> </form> </div> </body> </html>

Imagen 5. Mostrar modelo
Rutas
Creamos el archivo product.js dentro de la carpeta /routes:
var express = require('express'); var router = express.Router(); var product = require('../controllers/ProductController.js'); router.get('/', product.list); router.get('/show/:id', product.show); router.get('/create', product.create); router.post('/save', product.save); router.get('/edit/:id', product.edit); router.post('/update/:id', product.update); router.post('/delete/:id', product.delete); module.exports = router;
y añadir la siguiente linea al archivo app.js en la raíz de la aplicación:
var products = require('./routes/products');
Con esto terminamos la aplicación esqueleto con CRUD de un modelo en NodeJS.
Anexo
El código fuente se puede encontrar en mi cuenta de Github con el enlace: https://github.com/arturoverbel/nodejs_skeleton.
Fuentes
- https://www.tutorialspoint.com/nodejs/index.htm
- https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs
- https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose
- https://www.djamware.com/post/58b27ce080aca72c54645983/how-to-create-nodejs-expressjs-and-mongodb-crud-web-application
July 18, 2018 at 11:09 am
Genial, aunque sería mejor que lo montaras con Docker para que la inicialización quede automatizada.
July 22, 2018 at 3:43 pm
YP! Gracias. Voy a trabajarlo con Docker a la próxima
July 19, 2018 at 8:20 pm
Excelente manual!!!
July 22, 2018 at 3:43 pm
Gracias 😉
March 1, 2019 at 6:15 pm
excelente introduccion, cualquier post me avisas por mi correo ingenieropol.2013@gmail.com, soy Pol Cristobal