Loading Node.js modules dynamically based on route

前端 未结 3 1254
情话喂你
情话喂你 2020-12-02 13:47

I\'m doing a project in Node.js using express. Here\'s my directory structure:

root
|-start.js
|-server.js
|-lib/
|    api/
|        user_getDetails.js
|             


        
相关标签:
3条回答
  • 2020-12-02 14:10

    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');    
        }
    };
    

    dynamizing this code a little bit you can do magic things :D

    0 讨论(0)
  • 2020-12-02 14:17

    If you know where your scripts are, i.e. you have an initial directory, for example DIR, then you can work with fs, for example:

    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
    

    Now your scripts need to follow the following structure (because of the require(path)(module_holder) line), for example:

    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;
    };
    

    and now, when handling a request, you do:

    // request is supposed to fire user_getDetails script
    module_holder['user_getDetails'](req, res);
    

    This should load all your modules to module_holder variable. I didn't test it, but it should work (except for the error handling!!!). You may want to alter this function (for example make module_holder a tree, not a one level dictionary) but I think you'll grasp the idea.

    This function should load once per server start (if you need to fire it more often, then you are probably dealing with dynamic server-side scripting and this is a baaaaaad idea, imho). The only thing you need now is to export module_holder object so that every view handler can use it.

    0 讨论(0)
  • 2020-12-02 14:17

    Here is an example of a REST API web service that dynamically loads the handler js file based on the url sent to the server:

    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);
    

    handlers in my case are in a subfolder /TrainerCentral, so the mapping works like this:

    localhost:8080/TrainerCentral/Recipe will map to js file /TrainerCentral/Recipe.js localhost:8080/TrainerCentral/Workout will map to js file /TrainerCentral/Workout.js

    here is a example handler that can handle each of the 4 main HTTP actions for retrieving, inserting, updating, and deleting data.

    /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");
       }
    };
    

    start the server from command line with "node index.js"

    Have fun!

    0 讨论(0)
提交回复
热议问题