Click here to Skip to main content
15,881,882 members
Articles / Database Development

NodeJS REST server trials to validate effective scripting

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
7 May 2012CPOL7 min read 36.5K   174   10  
Trial of popular REST implimentations for NodeJS including the measuring of MongoDB insertion rates.
  • rest-stress.zip
    • rest-stress
      • .git
        • COMMIT_EDITMSG
        • config
        • description
        • FETCH_HEAD
        • HEAD
        • hooks
          • applypatch-msg.sample
          • commit-msg.sample
          • post-commit.sample
          • post-receive.sample
          • post-update.sample
          • pre-applypatch.sample
          • pre-commit.sample
          • prepare-commit-msg.sample
          • pre-rebase.sample
          • update.sample
        • index
        • info
          • exclude
        • logs
          • HEAD
          • refs
            • heads
              • master
            • remotes
              • origin
                • HEAD
                • master
        • objects
          • 01
            • 0f1d7448768a22080ef394b21f138fc2193f07
          • 05
            • 26e7aae6d10a517dd4765d42fafb0af19976d7
          • 06
            • 7b5b3dd48bbf7c3836e3147f8b83092bf0b899
            • ef85cad33989b244fbd7d20801159c4c5daf42
          • 0b
            • 22d45bde518fec30f608e46741847e27c2a227
            • f89c06c1fa24c129abead9c07f9b2b2caf8b12
          • 0e
            • 021221d66219cee25fa7e5826001dd7ac6c22a
          • 11
            • e74ae401cf8ac8a01b12a20db6513cc498dd08
          • 13
            • 1f099f068e5c39faecb0d3bab4ebe83492e6c5
          • 16
            • af8a1b39b0e84e41aa3ba44a7150d2c83ca773
          • 17
            • 05fc02333c7a30bc50a6f64b85651f2c3cc6a5
            • a4d42e856295e53aa21168d283a0821c3ee38d
          • 1a
            • ff806678b579f68fb299806668974fac3821c9
          • 1c
            • acc486b33cd3b44f2a18c584c1cd4489afa80b
          • 21
            • 9f1684e8d19e3138718d727952ed4481c8c83e
          • 24
            • 8fc6007f35c263eed9cbba41c0fa39fbe87356
          • 25
            • 4db02248c396fd24e5cac1f9f1762a55a1aeda
            • e8ee73ee6d7b6a94d3aa594541ea7f309cb35e
          • 28
            • 4d6c1fa920f512ea767d15c718c8b5f511c99e
            • ae8188d0901343be58777bfb488e78c991d442
          • 29
            • 68355e74e030673667edb8a061f05176d4bb65
          • 2e
            • aa6bb4f7b69eac7ddc646c113cabb869a0eb6d
          • 30
            • 6eb5de416c3b65f780cc44e1fe146dc38a32bd
            • aef02ee4954a63acd7105a791828ed69fd7854
          • 33
            • 40d681d41c95f2abc17cafa2741174cd746e00
            • 724e6b9392ace7a781878e00d830ca47c718ea
          • 37
            • ec244f21f9685c9d49df2427033ce9f85664d3
          • 3f
            • e631d0aef1ab5c4c74c13fda28d9399f8048b6
          • 41
            • d20974ae6b044a58b6384bf78ead83d17b1da1
          • 43
            • f525e7c5d8cc1561d8f6923e5aeb72ed6c7e0f
          • 45
            • 74be6d37cab0537af0cc2c3592e77b2ad67695
          • 46
            • e305795c9fae4bb15d1b37bd62ef8605b5fe9d
          • 47
            • 0acc47549e22f7a2540e959370250b3204499f
            • 8a2044973989ebb4b590434302cfcd7f14b86a
          • 4a
            • 99ca196a3d1e104ae788fdcb00b5344bc82478
          • 4b
            • 6165ea045fd81a338f69f01aa821d76e8483cc
          • 4d
            • ae1b7e000b913572a5e80e02011e2b4fd1cb0c
          • 52
            • 6bb84f112a31f41bea52957600fc86ae41559b
          • 53
            • 09a03cd49df9862ca001cc95b91b50d1b1c0fb
          • 58
            • f539eb177da517f828a62a6e4e20491d56b22c
          • 5a
            • 5eae75a81da424297df32bb01a1e31ebef0356
          • 62
            • 6adaf1100b88a88ba7704a24fe644439bb8ef0
          • 63
            • 80a7d80fab7ec5f7be919bfd128d1d36aafe84
          • 65
            • 0055eee1b974bd7ae2846ddc9cc79a16d9eaea
          • 66
            • a346ffda8b5d750e0aaee21dd227846d859015
          • 69
            • 54b38ff63a85621d96584640f6a0d5ab2e5f59
            • fb9da154eefe36202fe545903076a48d3e3330
          • 6b
            • 8184f8eff8a84b43e35fa349b3bac12afe3215
          • 6f
            • 1d850bb09b5a80cf95df70c0c67fa93904585f
          • 78
            • 998884e829b0d40d80f6db7d1f07d2cc36a7a4
          • 7a
            • c2ba6a21ff564a8001f2d4bde8d38ad711999c
          • 82
            • 4d04474332701c3c9c186ec449574e2077cde6
          • 84
            • 9415ca6e401e966f661a16a38436a8c90d3e93
          • 89
            • cd00f13809daaa5e05e4b4f4be32b770b96792
          • 8a
            • ab628eeddfc8f31c23a97eee9b7c180856805a
          • 8b
            • 028b38ad4f24f33b39f94c258eaeb20d8746ad
            • 6f5779328a56ea26174f9bfa3b2c797a3cb017
          • 8e
            • 13c9e734a5d6d2a841f5c4e13613e9b2368138
            • 405c8ce83552a9de24b438259a69d66d645def
          • 91
            • dac53ce6ec6fa288640a24239cb9bc04d01d8f
          • 92
            • 2003b8433bcad6ce9778a37628d738faa26389
          • 93
            • 69e167f200638b416b648655f15d4671ce7372
          • 97
            • 4728cdda2729522c3707b96f0ed20431704c45
          • 9a
            • 9534c9ca489495b0c828d3058e1d88fa9ac3f7
          • 9b
            • 1a74e04bad1488892d8e5151a58fe5f8e49847
          • 9d
            • 32e507a9813290efcaf393d19f39eaa295ff9d
          • 9e
            • 65f2896866641a84250b78bb034b7102978643
          • a0
            • 58e566b1c25cd22b45e45e2cb7967462eb5616
          • a4
            • ea3f0c04ca2eee285398339d6a4f45516a6ad0
          • a5
            • b95bcbe48aa4219b6ba69045fa85b21e28b07f
          • aa
            • 48737d8579aa75f29de07cb4e526822fa0824b
            • d83e36abcec290099f34b94f4af5ed25e68c8e
          • ac
            • 56460aefd760b09e1e228fe70a67ad437f941d
            • 798ac3c717073966656c675102aa103ca3c155
          • ad
            • 9206e1de1b3185e3e7cc63d749f2023077ad5c
          • b2
            • 48c95c6ff9a5d970256e7ff116cd618079b877
          • b3
            • 014503c02df410ddbc359bc411cddc7a3c8b28
          • bf
            • d4cadf7c15d3ae194cd9728fb363e8b95a3bf6
          • c0
            • 69471c734258f6f6a284faf3d8b21486dedcc1
          • c2
            • ee439b5e90c14d63f6e982097222debe7f7745
            • f87f3bca2050f6d36ef8ce88942aed7b6e23db
          • c7
            • 0699792ffc4d7531b59306ab33453a24cb25b5
          • cd
            • 032e0c6ec5b8e4333ae8a64cfc8eb57969d49c
          • d2
            • 83614f5cb28bb6bbe54441419e67b66c74f7ca
          • d4
            • f91d8db4fe56ad1038c5faeb25a970b8434d26
          • d5
            • b1eea6885c9d8b5fece918ff7573218062d8cc
          • da
            • cd787248e03b22ad13340ff6898602ec270d76
          • dc
            • a33b829875c8a947742ae39b89d3255335f175
          • df
            • efdf3a685d4d3773384002488a6414ff1033da
          • e2
            • 06d70d8595e2a50675ba11de48efcfa012497d
            • a6f487c8104409a4a8817c0e5cb5bd7837be82
            • d2f9780b0367f5cb1dc66d46ecea380f7b90c2
          • e5
            • ef752b760e7fb29553349b5dcec4c8da094bb1
          • e7
            • 911bdf58513ace76db9f20a59d2876f8b64d51
          • eb
            • d747c7d39320ff069f9d4ff52ad59f9e13d3b1
          • ee
            • 3b182e3325d8bd9ebf52ce90708ac902c637ea
          • ef
            • 732009884af9b6b096e81811b0d46bb1524342
          • f2
            • 473e9ed146bd5d6f06ae6761bbb17359bfdb63
          • f3
            • 307d0edb28d23039c48cebcf2ba4862ba28407
            • fc637e36f3e86191eae658136895976a5bf6d8
          • f5
            • ea78e3a497b94f62410babadd2e3619ae523bd
          • fd
            • 0ec436e2794aa773c59af655dcf69a4c961c51
            • b9aaab713a7ac121e3b1e1cf6af7b5a6c9a5c1
          • info
          • pack
        • ORIG_HEAD
        • packed-refs
        • refs
          • heads
            • master
          • remotes
            • origin
              • HEAD
              • master
          • tags
      • .idea
      • client.js
      • client-restify.js
      • docs
      • images
        • mongoInsertTrend.png
        • restMongoComparedRate.png
        • restMongoOverhead.png
        • restMongoRate.png
        • restOverhead.png
        • restRate.png
        • restSingleMongoRate.png
      • lib
      • README.md
      • servers
var http = require('http');
var codes = require('./codes');

module.exports = function() {
    var rest = function(route) {
        return rest.handlers(rest.router.add(route));
    };
    rest.matchDefs = {};
    rest.respond = function(res, code, headers, data) {
        if (code && headers && !data) {
            data = headers;
            headers = {};
        } else if (code && !headers && !data) {
            data = code;
            code = 200;
            headers = {};
        }

        if (typeof data === 'object') {
            data = JSON.stringify(data);
            headers['Content-type'] = headers['Content-type'] || 'application/json';
        }

        if (!headers['Content-length'] && typeof data === 'string') {
            headers['Content-length'] = data.length;
        }

        // TODO: streams, json, html (look for <)
        res.writeHead(code, headers);
        res.end(data);
    }
    rest.handlers = function(route){
        route.methods = route.methods || {};

        route.methods.options = route.methods.options || function(ctx) {
            var methods = Object.keys(route.methods).filter(function(key) {
                return key !== 'options';
            });

            ctx.respond(200, methods);
        };

        route.method = function(rawVerb, accept, fn) {

            if (rawVerb && accept && !fn) {
                fn = accept;
                accept = null
            }

            var verb = rawVerb.toLowerCase();
            if (verb[0] != 'p') {
                route.methods[verb] = function(req, res, segments) {
                    fn(req, res, segments);
                };
            }else{
                route.methods[verb] = function(req, res, segments) {
                    var body = '';
                    req.on('data', function (data) {
                        body += data;
                        if (body.length > 1e6) {
                            // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
                            req.connection.destroy();
                        }
                    });
                    req.on('end', function () {
                        //TODO: Switch contentType

                        var data = body;// JSON.parse(body);
                        fn(req, res, segments, data);
                    });
                 }
            }
            return route.method;
        };
        return route.method;
    };

    rest.router = (function() {
        var routes = {};

        return {
            add : function(url) {
                var location = routes;
                var urlMatch = url.replace(/[\-[\]\{\}\(\)\*\+\?\.,\/\\\^\$\|#\s]/g, "\\$&").replace(/(:[^(\\/)]+)/g,"([^/]*)");
                var patternRE = new RegExp(urlMatch);
                var paramKeys = (url.indexOf("/:")) ? url.replace(/(\/[^:][^\/]+)/g, '').substr(2).split("/:") :[];
                location[urlMatch] = rest.handlers({});
                rest.matchDefs[urlMatch] = {re:patternRE, paramKeys:paramKeys};
                return location[urlMatch];
            },
            handle : function(req, res) {
                // Handle options

                var method = req.method.toLowerCase();

                var location = routes;
                var paramKeys;
                var params={};
                for (var pattern in rest.matchDefs) {
                    var urlParams = req.url.match(rest.matchDefs[pattern].re);
                    if ( urlParams != null){
                        // Align variables in the URL with the REST definition
                        var paramKeys = rest.matchDefs[pattern].paramKeys;
                        for(var ikey=0; ikey < paramKeys.length; ikey++)  {
                            params[paramKeys[ikey]] = urlParams[ikey + 1];
                        }
                        location = routes[pattern];
                        break;
                    }
                }

                if (!location.methods || !location.methods[method]) {
                    return rest.respond(res, 501, {'Content-type' : 'text/plain'}, 'Not Implemented');
                }

                location.methods[method](req, res, params);

            },

            respond : function(code, headers, data) {
               rest.respond(res,code, headers, data);
            }
        }
    })()

    rest.listen = function(host, port, cb) {
        http.createServer(rest.router.handle).listen(host, port, cb);
    };

    return rest;
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Relavance
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions