Hola comunidad. En esta ocasión me gustaría seguir adicionando funcionalidades al servidor web desarrollado en mi entrada anterior [humanCode] Construyendo un servidor web con NodeJS , para con ello seguir adentrándonos en el desarrollo de aplicaciones con NodeJS. Hoy les explicaré cómo agregar un módulo para la gestión de controladores para, al igual que hace Apache o cualquier otro servidor web, dar respuesta a las peticiones que necesitan procesamiento en el servidor, en el caso de Apache estaríamos hablando de los archivos .php en los cuales se implementa la lógica de negocio, en el nuestro hablamos simplemente de un archivo .js que exporte las funcionalidades que brinda.
NodeJS_LogoBueno, manos a la obra. Lo primero que vamos a hacer es agregar una función al archivo basicServer.js, dentro de la función createServer que nos permita añadir un contenedor para el manejo de los controladores (algo así como el libapache2-mod-php5), acá el código:

htserver.controller = function(host, path, controllerPath){
    return this.addContainer(host, path, require('./controllerManager'),{
      controllerPath: controllerPath
    });
  }

En esta función lo que hacemos es indicar que para un host y un path entrados por parámetros, el módulo que se ejecutará sera el controllerManager, además, se especifica el directorio donde guardaremos los controladores. Luego de haber hecho esto pasamos al archivo server.js y en el llamamos a la función que acabamos de crear, el archivo quedaría así luego de los cambios:

var port = 8888;
var server = require('./basicserver.js').createServer();
server.useFavIcon("localhost", "./www/favicon.png");
server.controller("localhost", "/controller/", "./www/controllers");
server.docroot("localhost", "/", "./www");
server.listen(port);

La 4ta línea es la que hemos agregado y en ella indicamos que para el host localhost y para las direcciones del tipo http://host:port/controller/* será el módulo controllerManager el que se ejecutará, además indicamos que nuestros controladores se guardarán en la carpeta /www/controllers del proyecto. Bueno, llegó la hora de crear el tan mencionado módulo controllerManager, para ello creamos un archivo controllerManager.js con el código que sigue:

var fs = require('fs');
exports.handle = function(req, res) {
  if (req.method !== "GET") {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("invalid method " + req.method);
  } else {
    var fname = req.basicServer.container.options.controllerPath + (req.basicServer.urlparsed.pathname).replace("controller/","");
    if (fname.match(/\/$/)) fname += "main.js";
    fs.stat(fname, function(err, stats) {
      if (err) {
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end("controller " + fname + " not found " + err);
      } else {
        var action ="main";
        var parameters = {request:req, response:res};
        parameters.parameters = {};
        if (req.basicServer.urlparsed.query.action){
          action = req.basicServer.urlparsed.query.action;
        }
        if (req.basicServer.urlparsed.query.parameters){
          parameters.parameters = req.basicServer.urlparsed.query.parameters;
        }
        var controller = require(fname)[action] ? require(fname)[action] : function(parameters){res.writeHead(200, {'Content-Type': 'text/plain'});res.end("No existe una funcion "+action+" en el controlador "+fname.replace(req.basicServer.container.options.controllerPath+"/",""));};
        var result = controller(parameters);
        res.end();
      }
    });
  }
}

Lo primero que hacemos es importar el módulo filesystem (fs) para el trabajo con, como su nombre indica, los archivos. A continuación, y muy importante, exportamos la función handle que es la que se llama a la hora de ejecutar el módulo, a continuación validamos que el método utilizado en la petición sea el GET, si es así pasamos a crear la ruta hasta nuestro controlador con la línea:

var fname = req.basicServer.container.options.controllerPath + (req.basicServer.urlparsed.pathname).replace("controller/","");

El valor de controllerPath lo pasamos como parámetro en el archivo server.js, esto nos permite tener controladores alojados en distintas direcciones. El pathname es, por ejemplo en la url http://localhost:8888/controller/main.js, /controller/main.js, o sea lo que viene después del host y el puerto. En este caso eliminamos la palabra controller de la ruta ya que esta solo la vamos a utilizar para saber que la petición se refiere a un controlador y no a un fichero .js del lado del cliente.

Por defecto se asume que si no se explicita un controlador este sea main.js, al igual sucede si no se pasa por GET una acción, esta será main.js.

Luego comprobamos que el controlador exista y si es así pasamos a capturar los valores action y parameters pasados por GET, en el caso de este último su valor debe ser un json y por defecto se le agrega referencias al request y al response para poder utilizarlas en los controladores. Por último se verifica que la función que se solicita es parte del controlador citado, o se crea una por defecto que reporte el error, en la línea:

var controller = require(fname)[action] ? require(fname)[action] : function(parameters){res.writeHead(200, {'Content-Type': 'text/plain'});res.end("No existe una funcion "+action+" en el controlador "+fname.replace(req.basicServer.container.options.controllerPath+"/",""));};

Aquí me gustaría señalar esta forma de llamar a una función de un módulo pasándola entre corchetes, esto nos devuelve el código de la función en cuestión, luego la podemos ejecutar de esta forma:

var result = controller(parameters);

Bueno, hasta aquí el código, ahora me gustaría indicarles algunos ejemplos de urls y sus respuestas:
URL tipo 1

URL tipo 2
URL tipo 3Bueno, hasta aquí la entrada de hoy, debajo les dejo el comprimido con los archivos añadidos y actualizados, así como un ejemplo de petición desde una página hacia un controlador. Espero les halla parecido interesante el artículo de hoy. Hasta una próxima entrada.

Server.zip (159 descargas)