javascript - principiantes - Cargando módulos de Node.js dinámicamente basado en la ruta
node js tutorial (3)
Estoy haciendo un proyecto en Node.js usando Express. Aquí está mi estructura de directorio:
root
|-start.js
|-server.js
|-lib/
| api/
| user_getDetails.js
| user_register.js
El directorio lib/api/
tiene varios archivos JS relacionados con la API. Lo que necesito hacer es crear una especie de sistema de enlace, que siempre que una de las funciones de la API se solicita desde el servidor HTTP expreso, realiza cualquier acción que se especifique en el controlador de API correspondiente. Probablemente sea confuso, pero espero que se te ocurra la idea.
- Larry envía una solicitud a través de POST para obtener los detalles del usuario.
- El servidor busca en
lib/api
para encontrar la función asociada con esa solicitud. - El servidor lleva a cabo acciones y envía datos a Larry.
Espero que me puedas ayudar. Estaba pensando que podría hacerse usando prototipos, aunque no estoy seguro.
¡Gracias!
Este es un ejemplo de un servicio web REST API que carga dinámicamente el archivo js del manejador en función de la url enviada al servidor:
server.js
var http = require("http");
var url = require("url");
function start(port, route) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Server:OnRequest() Request for " + pathname + " received.");
route(pathname, request, response);
}
http.createServer(onRequest).listen(port);
console.log("Server:Start() Server has started.");
}
exports.start = start;
router.js
function route(pathname, req, res) {
console.log("router:route() About to route a request for " + pathname);
try {
//dynamically load the js file base on the url path
var handler = require("." + pathname);
console.log("router:route() selected handler: " + handler);
//make sure we got a correct instantiation of the module
if (typeof handler["post"] === ''function'') {
//route to the right method in the module based on the HTTP action
if(req.method.toLowerCase() == ''get'') {
handler["get"](req, res);
} else if (req.method.toLowerCase() == ''post'') {
handler["post"](req, res);
} else if (req.method.toLowerCase() == ''put'') {
handler["put"](req, res);
} else if (req.method.toLowerCase() == ''delete'') {
handler["delete"](req, res);
}
console.log("router:route() routed successfully");
return;
}
} catch(err) {
console.log("router:route() exception instantiating handler: " + err);
}
console.log("router:route() No request handler found for " + pathname);
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("404 Not found");
res.end();
}
exports.route = route;
index.js
var server = require("./server");
var router = require("./router");
server.start(8080, router.route);
los manejadores en mi caso están en una subcarpeta / TrainerCentral, por lo que el mapeo funciona así:
localhost: 8080 / TrainerCentral / Recipe se asignará al archivo js /TrainerCentral/Recipe.js localhost: 8080 / TrainerCentral / Workout se asignará al archivo js /TrainerCentral/Workout.js
Aquí hay un controlador de ejemplo que puede manejar cada una de las 4 acciones HTTP principales para recuperar, insertar, actualizar y eliminar datos.
/TrainerCentral/Workout.js
function respond(res, code, text) {
res.writeHead(code, { "Content-Type": "text/plain" });
res.write(text);
res.end();
}
module.exports = {
get: function(req, res) {
console.log("Workout:get() starting");
respond(res, 200, "{ ''id'': ''123945'', ''name'': ''Upright Rows'', ''weight'':''125lbs'' }");
},
post: function(request, res) {
console.log("Workout:post() starting");
respond(res, 200, "inserted ok");
},
put: function(request, res) {
console.log("Workout:put() starting");
respond(res, 200, "updated ok");
},
delete: function(request, res) {
console.log("Workout:delete() starting");
respond(res, 200, "deleted ok");
}
};
iniciar el servidor desde la línea de comandos con "node index.js"
¡Que te diviertas!
Si sabe dónde están sus scripts, es decir, tiene un directorio inicial, por ejemplo, DIR
, entonces puede trabajar con fs
, por ejemplo:
server.js
var fs = require(''fs'');
var path_module = require(''path'');
var module_holder = {};
function LoadModules(path) {
fs.lstat(path, function(err, stat) {
if (stat.isDirectory()) {
// we have a directory: do a tree walk
fs.readdir(path, function(err, files) {
var f, l = files.length;
for (var i = 0; i < l; i++) {
f = path_module.join(path, files[i]);
LoadModules(f);
}
});
} else {
// we have a file: load it
require(path)(module_holder);
}
});
}
var DIR = path_module.join(__dirname, ''lib'', ''api'');
LoadModules(DIR);
exports.module_holder = module_holder;
// the usual server stuff goes here
Ahora sus scripts deben seguir la siguiente estructura (debido a la línea require(path)(module_holder)
), por ejemplo:
user_getDetails.js
function handler(req, res) {
console.log(''Entered my cool script!'');
}
module.exports = function(module_holder) {
// the key in this dictionary can be whatever you want
// just make sure it won''t override other modules
module_holder[''user_getDetails''] = handler;
};
Y ahora, al manejar una solicitud, haces:
// request is supposed to fire user_getDetails script
module_holder[''user_getDetails''](req, res);
Esto debería cargar todos tus módulos a la variable module_holder
. No lo probé, pero debería funcionar (a excepción del manejo de errores !!! ). Es posible que desee modificar esta función (por ejemplo, hacer que module_holder
un árbol, no un diccionario de un nivel) pero creo que entenderá la idea.
Esta función debe cargarse una vez por inicio del servidor (si necesita activarlo más a menudo, entonces probablemente esté trabajando con scripts dinámicos del lado del servidor y esta es una idea baaaaaad, imho). Lo único que necesita ahora es exportar el objeto module_holder
para que todos los controladores de vistas puedan usarlo.
app.js
var c_file = ''html.js'';
var controller = require(c_file);
var method = ''index'';
if(typeof(controller[method])===''function'')
controller[method]();
html.js
module.exports =
{
index: function()
{
console.log(''index method'');
},
close: function()
{
console.log(''close method'');
}
};
Dinamizando un poco este código puedes hacer cosas mágicas: D