1. Introducción

Hola y bienvenidos a todos a un nuevo post de nuestro querido blog!. En esta ocasión nos vamos a adentrar en el mundo de NodeJS. La idea principal va a ser crear nuestro primer proyecto en esta tecnología. Para ello instalaremos node, crearemos un proyecto utilizando express y levantaremos nuestra primera aplicación. He de admitir que éste es un post especial ya que es la primera vez que aparcamos nuestro querido mundo Java para adentrarnos en otros universos.

Node.js es un entorno multiplataforma basado en el lenguaje de programación ECMAScript, asíncrono, orientada a eventos y basado en el motor V8 de Google. Fue creado por Ryan Dahl en 2009 y su evolución está apadrinada por la empresa Joyent. Entre las características mas destacables podemos señalar:

  • Basado en Javascript en el servidor
  • Rápido desarrollo
  • Flexible
  • Escalable
  • Modularizable gracias a su gestor de paquetes npm
  • Basado en eventos

Os podéis descargar el código de ejemplo de mi GitHub aquí.

Tecnologías empleadas:

  • NodeJS 6.11.0
  • Npm 3.10.10
  • Express 4.15.2

2. Instalación y preparación del entorno

Lo primero que tenemos que hacer es descargarnos el ejecutable de NodeJS de la web oficial https://nodejs.org para proceder con la instalación. Una vez terminado tendremos disponibles los siguientes elementos en nuestra máquina:

  • nodejs. Core a través del cual podremos ejecutar nuestras aplicaciones en servidor escritas en javascript
  • npm. Gestor de paquetes a través del cual gestionaremos nuestras dependencias

Para verificar que la instalación se ha realizado de forma correcta bastará con hacer

node -v
v6.11.0

3. Creación del proyecto

Utilizamos las conocidos módulos express y express-generator para generar la estructura de nuestro proyecto web.

Los instalamos de forma global.

npm install -g express
npm install -g express-generator

Finalmente creamos nuestro proyecto que denominamos NodeJsMongoDBHelloWorld

express NodeJsMongoDBHelloWorld

Quedando una estructura de carpetas tal que así:

En el fichero package.json se defines los módulos que vamos a necesitar en nuestra aplicación.

{
  "name": "nodejsmongodbhelloworld",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.17.1",
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.3",
    "express": "~4.15.2",
    "jade": "~1.11.0",
    "morgan": "~1.8.1",
    "serve-favicon": "~2.4.2"
  }
}

Dichas dependencias deben ser instaladas para que se puedan ser utilizadas en tiempo de compilación. Para ello bastará con hacer:

npm install

Una vez finalizado el comando anterior deberíamos ver los diferentes módulos descargados en el directorio node_modules

4. Arranque del proyecto

Para arrancar nuestra primera aplicación node es suficiente con ejecutar el siguiente comando desde un terminal situándonos en la raiz del proyecto.

npm start

y entrar en la url http://localhost:3000

5. Análisis de los ficheros principales

El fichero principal de nuestro proyecto es el app.js en donde se definen la ubicación de las vistas, el motor que las resuelve (se utiliza por defecto jade), los controladores de nuestra aplicación o los tipos de formato que se van a aceptar.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Los controladores se definen con convenio en los ficheros route en donde establecemos la función que se debe ejecutar en función del método y la url invocada.

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

Por otra parte las vistas las podemos encontrar en el directorio views

extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack}
extends layout

block content
  h1= title
  p Welcome to #{title}
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content

Hemos indicado anteriormente que para llevar a cabo el arranque del servidor web debemos utilizar el comando npm start sobre un terminal. Esto arrancará un script que se define en el fichero package.json "start": "node ./bin/www"

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('nodejsmongodbhelloworld:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

Una de las cosas que más llama la atención es que, a diferencia de otras tecnologías como Java donde para levantar un servidor web necesitamos un Tomcat o un servidor de aplicaciones, en nodejs el servidor lo creamos en el arranque de la aplicación.

var server = http.createServer(app);