Apper

Plug and play, restful, real-time application framework for single page apps

Apper

Plug and play, restful, real-time application framework for single page apps.

Build Status on Travis CI NPM Latest version

App

A regular directory becomes a valid app if it has one or more of the following:

All of the default file/directory names above can be changed by options in apper.json file in any directory.

Install

For usage as command-line tool:

$ npm install -g apper

For usage in code:

$ npm install apper

Usage

From command-line

Just open the shell (or command prompt) in the app directory (with one or more of the above-mentioned files), and run:

$ apper

And open http://localhost:8000 in browser.

Run apper -h for all the command-line options.

A more specific deployment might look like:

$ apper --port 8080 --address 127.0.0.0 code/src

Here, code/src is the root path of the application code, relative to current directory from which apper is run. It defaults to the current directory itself.

To display internal logs during development (helpful), just set DEBUG environment variable to apper:*

$ DEBUG=apper:* apper --port 8000

For a working example, check out test/sample which is used by the tests. Just run apper in the shell there and read the tests to get a better understanding.

Motivation

Express isn't enough. It lacks structure and conventions.

Apper provides:

The core idea of apper is to enable easy REST api based node.js apps, especially useful for Single Page Applications.

Apper lets you create bigger apps by using smaller independent chunks as subapps. Simply place individual subapps anywhere in the directory hierarchy, and they get exposed under a relative base URL.

Nested subapps are totally cool and highly encouraged. In fact, simply by moving a subapp directory to another directory updates the exposed relative URL of that subapp. No frills.

Example

Example directory structure

+ root/
.... server.js (See Programmatic Usage section below)
.... routes.js (GET /login)
    + public/
    .... index.html
    .... main.js

    + api/
    .... routes.js (GET /, POST /)

        + items/
        .... middleware.js
        .... routes.js (GET /, GET /last)

routes.js files above are supposed to specify route handlers for paths mentioned against them.

Read below for code samples for all of them.

API exposed by the directory structure above

GET  /
GET  /login

GET  /api
POST /api

GET  /api/items
GET  /api/items/last

The route / serves index.html in public/ by default. Can be overridden by including a route GET / in routes.js.

Core Concepts

Order of initialization of modules

The following modules get initialized on the subapp in order:

Bigger apps composed of small apps

The root app can contain sub-directories which are complete apps unto themselves. These directories become subapps of the root app (or sub APIs, if you may).

Subapps can be pulled out and placed anywhere in the overall directory structure. This would make them available on the new relative url with respect to the root.

Every subapp directory can be started as a separated app just by running apper in there.

Due to the directory hierarchy based mounting of subapps, the base URL paths of all subapps are decided by their position in the directory hierarchy.

The subapps can then register for any relative URL route after their base URL and handle requests accordingly.

Programmatic Usage

As a module

Create a file (say, server.js) in your application directory

var app = require('apper')({
    port: 8000
});
app.start();

Then, running server.js will start the application on port 8000. For example:

$ node server.js

To see internal logs (helpful during development), just set the environment variable DEBUG as follows:

$ DEBUG=apper:* node server.js

As Express application

Create an application object as usual, and use app.expressApp as a regular express application

var app = require('apper')();
app.expressApp.listen(5000);

As Express middleware

You can use this application as middleware in your regular express app as follows:

var app = require('apper')();
myExpressApp.use(app.expressApp);

Mounting your apper app as an Express subapp is as easy:

var app = require('apper')();
myExpressApp.use('/blog', app.expressApp);

Now the apper application gets confined to /blog base URL.

More Code

Startup

Apper synchronously loads its modules when you initialize it. You can start the server by calling app.start().

Constructor options look like this:

var app = require('apper')({
    path: '.',
    port: 8000,
    host: '0.0.0.0',

    // Not commonly used. Just use `apper.json` for the configuration
    toOpenBrowser: false,
    staticDir: 'public',
    moduleNames: {
        environment: 'environment'
        middleware: 'middleware',
        routes: 'routes',
        sockets: 'sockets'
    },
    mountPath: ''
});
app.start();

The default values for the options (path/port/etc) are as shown above. The options mean the following:

Server automatically starts a single socket.io WebSocket server that works across all subapps but maintains separate namespaces for all communication with different subapps.

Structure of modules

Get an Express-based app object and run express methods like app.set, app.use, app.get, app.post, etc. on it.

For WebSocket requests, app.sockets provides the same functionality as io.sockets using socket.io

environment.js

module.exports = function (app) {
    app.set('property', 'value');
    // Environment configuration
};

middleware.js

module.exports = function (app) {

    app.use(function (req, res, next) {
        // middleware code
        next();
    });
};

routes.js

module.exports = function (app) {

    app.get('/', function (req, res) {
        res.send('hey');
    });
};

sockets.js

module.exports = function (app) {
    app.sockets.on('connection', function (socket) {

        socket.on('hey', function (name) {
            socket.emit('Hey ' + name + '!');
        });

    }
};

Client-side socket code

Client-side code corresponding to sockets.js looks as simple.

Just include <script src='/socket.io/socket.io.js'></script> in public/index.html, and connect to the socket server like this:

var socket = io();

socket.on('connect', function () {
    alert('woohoo!');
});

A subapp client connects by default to its own namespace, as per its directory hierarchy. So you won't have 2 different subapps catching each others socket events.

Configuration

apper.json placed in root or any subapp directory controls the following configuration for the respective app:

Sample apper.json configuration file

{
    "moduleNames: {
        "environment": "env",
        "middleware": "mid",
        "sockets": "sock",
        "routes": "route-definitions"
    },
    "staticDir": "www",
    "dirToIgnore": ["subapp", "another"],
    "bundle": true
}

Tests

To run tests yourself, install mocha

$ npm install
$ npm install -g mocha

In the project directory, run

$ npm test

Check out the test directory for usage examples.

License

MIT