Writing a simple API with Node.js

Hey, everyone.

Here's a way of having a good-looking simple Node.js API without having to search for what you need a long time.

The beginning

I use express.js. And here's how to start:

var express = require('express'),
    app = express(),
    port = 5555;

// listen to this specific port
app.listen(port);

// for the post requests we need to parse the data
app.use(require('connect').bodyParser());

Versions

Let's start with this one.
All APIs have versions. Some just add functionality, but others change over time.

I need to catch requests. It's best to match a group of requests. Express provides methods for catching only get requests, only post requests... or all at once.
It's best here to catch all requests and later execute what I need.

// match /v1 calls; skip potential problems
app.all(/^\/v1(\/|$)/, api_requests);

This one would match /v1 and /v1/something but not /v123. Which is what I want.
I say when a /v1 request comes - execute api_requests.

I also need to load the version for this API.

versions['1'] = require('./versions/version1');

Here's the place to say I have additional files to transform the url, filter it, get the API version and so on.

var api_requests = function(req, res){
    var request_url = req.url,
        url = helper.get_url(request_url),
        version = helper.get_version(request_url),
        endpoint = helper.get_endpoint(request_url),
        method = helper.get_method(req);

    versions[version].init({
        loader: require('./loader'),
        db: require('./db').init(),
        print: res
    });

    try{
        // ex: versions[1][comments][get].apply(null, [comments, all])
        versions[version][endpoint][method].apply(null, url);
    }catch(ex){ // catch the ex hohoh
        console.log('invalid request', req.url, req.headers, req.connection.remoteAddress);
        res.json([]);
    }
};

So by doing this whatever request comes the API would execute the function named like the endpoint we are requesting.

Loader

I have a loader file which loads the methods and modules I'll use:

/**
 * It's important to provide context for the functions here!
 */

var e = {
    load_modules: function(modules, config){
        for(var i in modules){
            var module = modules[i];

            this[module] = require('./versions/modules/' + module).init(config);
        }
    },

    load_methods: function(module, methods, config){
        for(var i in methods){
            var method = methods[i];

            this[method] = require('./versions/modules/' + module + '/' + method).init(config)[method];
        }
    }
};

module.exports = e;

Loading all modules

Loading all modules that I want to use for this API version. This is the version1 file.

/**
 * Here we load all modules that are allowed to be used.
 * The load_modules in the context of this object will
 * make keys on this for each module whose value will be the module itself =
 * object with keys the rest methods.
 */

var e = {
    init: function(config){
        var modules = ['comments'];

        config.loader.load_modules.apply(e, [modules, config]);
    }
};

module.exports = e;

Loading all methods

In order to achieve this when calling the init method of the versions[version] here's what happenes:

/**
 * This module loads its methods using loader's load_methods in the context of
 * this object here.
 * The load_modules will make keys on this object with the
 * supported methods whose value will be the method itself.
 */

 var e = {
    init: function(config){
        var module = config.common.get_filename(__filename),
            methods = ['get'];

        config.loader.load_methods.apply(e, [module, methods, config]);

        return e;
    }
};

module.exports = e;

It loads the methods from methods and sets them as keys here. After this operation I'll have keys init and get on this module.

And when called get, the get method will execute itself.

The get is loaded from /versions/modules/get which means that modules are version-indipendent or at least in my case. In my case some modules are available in the newer API versions. In yours it may be better to be version-dependent which you can achieve easily.

Methods

/**
 * A file that consists of the 'get' method and others that 'get' calls whenever
 * it needs them.
 * All the other rest methods are in different files.
 */

var db,
    print;

var e = {
    init: function(config){
        db = config.db;
        print = config.print;

        return e;
    },

    get: function(){
        db.query("SELECT * FROM comments;", function(err, data){
            print.json(data);
        });
    }
};

module.exports = e;

That's the way a get method file looks like. It has get and other functions if it needs to call for a reason. It receives a config file with the db connection and printing function.

That's it

You'll say what's simple there?
The simple part is that to add something new you only need to add it as an allowed rest method and write the code in the file.

Have a nice weekend

.. or a nice workday. :)

.. and sorry this article has no graphics. :)

Lucky giraffe