Si estás considerando hacer una web con NodeJS es muy recomendable que uses un framework que te facilite la tarea en vez de hacer todo desde cero, y mi recomendación es que uses ExpressJS. Para que sepas cómo empezar te propongo esta introducción con la que reparasermos las nociones básicas para entender este interesante framework.
Hola, soy malnuer, y te voy a guiar por el camino de la creación de páginas webs con Javascript usando NodeJS. Si has usado alguna vez un lenguaje de servidor como por ejemplo PHP, ya sabrás que tenías a tu disposición un montón de funciones y variables que daban acceso a todo lo necesario para manejar el comportamiento de una web. Me refiero a las variables GET, datos POST, la gestión de sesiones, la carga de archivos (FILE), las Cookies, archivos estáticos… Con NodeJS no tenemos, en principio, ninguna de estas cosas, sólo recibiremos la petición HTML con sus cabeceras. Así que la mala noticia es que lo demás tenemos que construirlo nosotros.
Por otro lado, la buena noticia es que alguien ya lo ha hecho, lo ha hecho muy bien, y lo ha compartido con todo el mundo. Estoy hablando de TJ Holowaychuck y de su framework ExpressJS, que a día de hoy es el estándar de NodeJS para hacer páginas web y que junto con MongoDB y AngularJS forman el conjunto MEAN Stack, que ahora mismo está de moda como solución potente y Open Source para poner en marcha cualquier proyecto web.

Express, framework web rápido, de mente abierta, minimalista para Node.js
Comparando NodeJS puro con ExpressJS
En un artículo anterior «Primeros pasos con NodeJS» vimos que poner en marcha un servidor era muy fácil, pero que de ahí a tener una web perfectamente funcional, nos quedaba mucho camino. Este era el aspecto que tenía la aplicación de servidor hecha con Node puro:
(Archivo: servidorPuro.js)
var http = require('http');
var servidor = http.createServer(function (peticion, respuesta) {
respuesta.writeHead(200, {'Content-Type': 'text/plain'});
respuesta.end('URL: '+peticion.url);
}).listen(1337);
console.log("Node escuchando en el puerto 1337");
Y ahora, este es el aspecto que tiene una aplicación con Express:
(Archivo: servidorExpress.js)
var express = require('express'); var app = express(); app.get('/', function (peticion, respuesta) { respuesta.send('Home'); }); app.get('/admin', function (peticion, respuesta) { respuesta.send('Administracion'); }); app.listen(3000); console.log("Express escuchando en el puerto 3000");
Antes de ver las diferencias entre ambos, te comento, por si acaso, cómo poner en marcha estos servidores: (si estás familiarizado con NodeJS seguro que no te hará falta esto, puedes saltártelo)
- El primero basta con copiar ese código en un archivo y llamarlo «servidorPuro.js«. Para ejecutarlo escribe «node servidorPuro.js» en la línea de comandos. Este capturará todas las peticiones HTTP que se hagan por el puerto 1337, por ejemplo:
http://localhost:1337/ejemplo/pagina - El segundo ejemplo, también tienes que copiar el código a un archivo y llamarlo «servidorExpress.js«, pero además hay que instalar ExpressJS con el NPM escribiendo «npm install express» dentro de la carpeta del proyecto. Después puedes escribir «node servidorExpress.js» para ejecutarlo. Este se encargará de capturar peticiones HTTP hechas a través del puerto 3000, como por ejemplo:
http://localhost:3000/admin
Ahora sí, vamos a ver las diferencias entre estos dos. A simple vista lo más evidente es que en el primer caso usamos el módulo «http» y en el segundo el de «express«. Después vemos que en el caso de NodeJS puro definimos el servidor con una función (azul) que se encargará de gestionar todas las peticiones, sean cuales sean. Mientras que cuando usamos ExpressJS podemos separar cada ruta y asignar una función (azul) diferente a cada una. Esto resulta mucho más útil y ordenado. Por último, en ambos casos indicamos qué puerto es el que queremos escuchar. Bien, el salto no ha sido muy traumático por ahora, ¿no? Vamos a ver un poco mejor cómo funcionan las rutas en Express.
El enrutador de ExpressJS
Vamos a centrarnos ya en Express, que es lo que nos interesa. Cuando definimos las rutas, podemos además diferenciar por el método HTTP (verbo) con el que estamos accediendo, así que podemos usar las siguientes funciones: app.get(), app.post(), app.put(), app.delete() y una última que los engloba a todos que es app.all(). Además, en la definición de la ruta podemos usar algunos operadores y comodines, como la interrogación, el signo de sumar, el asterisco o los paréntesis, e incluso si necesitas cosas mucho más complejas, siempre puedes recurrir a las expresiones regulares:
- app.get(«/abc?de»,function(peticion,respuesta) { … });
La interrogación implica que el carácter de delante sea opcional, así que esto coincidirá tanto con «/abcde» como con «/abde«. - app.get(«/abc+de»,function(peticion,respuesta) { … });
El signo de suma implica que el carácter de delante puede aparecer una o más veces, así que coincidirá con «/abcde» o «/abccde» o «/abcccccde» por ejemplo. - app.get(«/abc*de»,function(peticion,respuesta) { … });
El asterisco representa una cadena cualquiera, incluida la cadena vacía, así que coincidirá con «/abcde» o «/abcHOLAde» entre otras muchas opciones. - app.get(«/ab(cd)?e»,function(peticion,respuesta) { … });
Los paréntesis sirven para agrupar caracteres y poder aplicar la interrogación o el signo de sumar al grupo completo, así que coincidirá con «/abe» o «/abcde«. - app.get(/.*ita$/,function(peticion,respuesta) { … });
Y la última opción, mucho más potente, es poder usar expresiones regulares (fíjate que no hay comillas, no es un string), en el ejemplo coincidiría cualquier ruta que termine en «ita» como «paginita» o «administracioncita» pero no «pagina«, ni «administracion«.
Otra cosa buena a la hora de definir las rutas, es que podemos definir parámetros dentro de ellas que luego podremos recoger con el objeto «peticion.params«. Esto se hace poniendo el signo de dos puntos delante del nombre de la variable a la que se asignará el valor. Por ejemplo:
app.get('/usuario/:nombre', function (peticion, respuesta) { respuesta.send('USUARIO: '+peticion.params.nombre); });
Nota: El objeto que he llamado «peticion» (Objeto de tipo Request) guarda más cosas interesantes que puedes mirar aquí: Express 4.0 API – Request.
Con respecto al enrutamiento, todavía nos quedan un par de truquitos más, pero tampoco es necesario cubrir todas las posibilidades desde el primer momento y con lo dicho hay más que de sobra. Si quieres más información aquí te dejo este enlace: http://expressjs.com/guide/routing.html.
Introducción a los Middlewares
Pero sí hay una cosa que es realmente importante y que tenemos que ver. Consiste en hacer que una de estas definiciones de ruta capture la petición, haga algo y luego la «deje libre» para que la pueda coger otra. Esto, en esencia, es lo que se llama middleware y aunque esta forma de explicarlo no es muy estricta, creo que ahora mismo puede ser suficiente para tener una idea de cómo funciona. Vemos un ejemplo y lo iremos entendiendo mejor. Así se define un middleware:
app.get('/admin/*',function (peticion, respuesta, next) { console.log('Zona admin'); next(); });
El truco está en añadir un nuevo parámetro «next» a los argumentos de la función, que al final del todo se usará para ejecutarlo como una función. ExpressJS por dentro se encargará de rellenar todos esos datos, tú solo tienes que seguir esta estructura (la intención es poder encadenar las funciones). El resultado de ese código es que cualquier petición que esté dentro de la zona «admin» (lo que pone en la ruta) hará que se escriba el texto «Zona admin» en la consola y después, en vez de detenerse, seguirá comprobando si hay alguna otra ruta que cumpla con el patrón.
Esto viene muy bien porque te permite hacer cosas que luego se puedan usar en cualquier otro sitio dentro de la aplicación. Puedes definir un middleware que guarde información dentro del objeto «peticion«, ya que este objeto será el mismo que recibirán las demás funciones de rutas. En nuestro ejemplo, en vez de escribir «zona admin» podríamos comprobar los permisos del usuario o alguna configuración personal, y guardarla en peticion.usuario, para que después las otras funciones tengan acceso a esa información.
Esta es la verdadera importancia de los middleware. Hay muchos paquetes compatibles con Express que añaden funcionalidades especiales gracias a este método, como puede ser el manejo de cookies, datos post, debug…
Sin embargo, para ser riguroso, los middlewares no son exactamente iguales a las rutas, de hecho, lo normal es que en vez de usar app.get(), app.post(), etc, se definan con la función app.use:
app.use(function(peticion,respuesta,next){ ... next(); });
Que la verdad es, que a efectos prácticos, y salvo algunas diferencias (que ya tendrás tiempo de entender), es casi lo mismo que usar:
app.all('*',function(peticion,respuesta,next){ ... next(); });
Al fin y al cabo, consiste en capturar todas las peticiones, sea cual sea la ruta y el método HTTP, hacer cosas para añadir funcionalidades al objeto «peticion» (Objeto Request) para que lo puedan usar los demás y luego ejecutar la función next(), para devolver el control al siguiente middleware o a alguna definición de ruta.
Servidor de recursos estáticos
Ahora quiero tratar el otro punto que vimos en el artículo anterior de Primeros pasos con NodeJS, que es el de poder servir archivos. En ese artículo vimos cómo hacer un servidor de recursos estáticos usando la librería «node-static«, ahora vamos a ver cómo se encarga ExpressJS de ese tema, y te va a encantar por lo fácil que es.
ExpressJS es capaz de devolver archivos estáticos con sólo decirle dónde están. Para eso basta con crear una carpeta, por ejemplo, «public«, meter archivos ahí, y decirle a ExpressJS que si alguien pide alguno de esos archivos, se los envie. Esto se consige con esta simple línea:
app.use(express.static('public'));
Nota: Puedes poner esta línea antes de las definiciones de rutas.
Vaya, ¿te has fijado? se trata de un middleware. Con esa línea estamos diciendo a ExpressJS que antes de empezar a comprobar si coincide alguna ruta, debe pasarle los objetos petición y respuesta a «express.static(‘public’)» que necesariamente será una función con la forma:
function(peticion,respuesta,next){ … next(); }
Si la ruta es un archivo, lo sirve, y si no lo es, seguirá comprobando las posibles rutas.
Con eso conseguimos que si tenemos un archivo: public/background.jpg
Podemos acceder a él con la ruta: localhost:3000/background.jpg
Fíjate que al indicar que la carpeta pública es «public«, ésta no aparece luego en las rutas.
Algunas cosas más antes de terminar
Para terminar, simplemente quiero hablar de algunas cosillas más que pueden hacer falta para hacer una web, y que hemos mencionado al principio:
- Variables GET: Estas variables se pueden coger del objeto Request, por ejemplo, si la URL es algo como: localhost/lista-usuarios?orden=ascendente, podemos coger el valor de la variable GET con: peticion.query.orden.
- Variables POST: Estos datos vienen todos apelotonados en el cuerpo de la petición y son un poco más complejos de extraer (podrían haber incluso archivos), así que hay que ayudarse de un paquete llamado «body-parser«. Una vez instalado, se usa como un middleware, y nos permitirá coger los datos de: peticion.body.nombreVar.
- Cookies: Con estas pasa algo parecido que con los datos POST, es preferible usar un paquete llamado «cookie-parser». Igualmente se instala, se usa como middleware, y los datos de cookies estarán disponibles en: peticion.cookie.nombreCookie.
Como ves, algunas cosas no vienen dentro de Express pero gracias a los middleware, se pueden añadir fácilmente. La plantilla básica recomendada para hacer una App Node con Express suele contener las siguientes librerías: body-parser, cookie-parser, debug, jade, morgan y serve-favicon. Todas estas cosas juntas y muchas más que existen por ahí, son las que hacen de ExpressJS el framework más potente y famoso de NodeJS.
Esto era solamente una toma de contacto y lo vamos a dejar aquí, pero en el siguiente artículo, empezaremos montando esa plantilla básica usando Express Generator, que es una utilidad que nos ayudará a crear un proyecto de Express con las librerías de la que te he hablado.