NodeAtlas

Controller and Model Part

NodeAtlas is useful for more than simply generate template web page easily based on your variation files. NodeAtlas allow you to dynamicly interact with variations var and with the DOM with;

  • parameters in query part of url (GET),
  • parameters in request body (POST),
  • connection with database or,
  • management of sessions or,
  • do AJAX or Websocket request/response and
  • do more !

Lifecycle and Hooks

For that, you could hook to some point of life cycle of the page generation with common controller (commonController) and with specific controller for each page (routes[<route>].controller).

This is a webconfig.json allows you to manipulate each part of life cycle of a page.

{
    "controllersRelativePath": "controllers",
    "commonController": "common.js",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.json"
        }
    }
}

Note : If controllersRelativePath is not present in "webconfig.json", default controller folder is controllers. controllersRelativePath is useful only to change the name/path of directory.

and this is the detail of all hooks :

Start NodeAtlas

Init of Modules

  • loadModules --> into commonController file (common.js for example).

Init of Sessions

  • setSessions --> into commonController file (common.js for example).

Init of server configuration

  • setConfigurations --> into commonController file (common.js for example).

Init of routes

  • setRoutes --> à manipuler depuis le fichier commonController (common.js dans l'exemple).

Start Web Server

HTTP Request/Response of NodeAtlas

Client Request Processing

  • changeVariation --> into commonController file (common.js for example).

  • changeVariation --> into routes[<route>].controller file (index.js for example).

Templates and Variations Compilation => Complete DOM.

  • changeDom --> into commonController file (common.js for example).

  • changeDom --> into routes[<route>].controller file (index.js for example).

Sending of Response to Client

changeVariation

In order to intercept variations, you could use common controller for all the website page and/or also a specific controller per page.

This is an example using the two hooks, the common in first and after the specific:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.js"
        }
    }
}

with this files :

├─ components/
│  ├─ head.htm
│  └─ foot.htm
├─ variations/
│  ├─ common.json
│  └─ index.json
├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ templates/
│  └─ index.htm
└─ webconfig.json

Do a POST request on http://localhost/?title=Haeresis with example=This+is+a+test variable in body will use the following files:

variations/common.json

{
    "titleWebsite": "Site Title"
}

variations/index.json

{
    "titlePage": "Welcome",
    "content": "<p>This is the Home Page.</p>"
}

templates/index.htm

    <%- include('head.htm') %>

    <div class="title"><%- common.titleWebsite %></div>

    <div>
        <h1><%- specific.titlePage %></h1>
        <%- specific.content %>
    </div>

    <%- include('foot.htm') %>

controllers/common.js

// This code is executed before variation are injected into template engine.
// This code is executed for all HTTP request, for all pages.
exports.changeVariation = function (params, next) {
    var variation = params.variation,
        request = params.request,
        response = params.response;

    // Here we update variations variable.

    console.log(variation.common.titleWebsite); // "Site Title"
    console.log(variation.specific.titlePage); // "Welcome"
    console.log(variation.specific.content); // "This is the Home Page."

    if (request.query["title"]) {
        variation.specific.titlePage = variation.specific.titlePage + " " + request.query.title;
    }
    if (request.body["example"]) {
        variation.specific.content = request.body.example;
    }

    console.log(variation.common.titleWebsite); // "Site Title"
    console.log(variation.specific.titlePage); // "Welcome Haeresis"
    console.log(variation.specific.content); // "This is a test"

    // We update modification here.
    next(variation);
};

controllers/index.js

// This code is executed before variation are injected into template engine.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
    var variation = params.variation,
        request = params.request,
        response = params.response;

    // Here we update variations variable.

    console.log(variation.common.titleWebsite); // "Site Title"
    console.log(variation.specific.titlePage); // "Welcome Haeresis"
    console.log(variation.specific.content); // "This is a test"

    variation.common.titleWebsite = "It's Home, no way.";
    variation.specific.content = "It's Home, no way.";

    console.log(variation.common.titleWebsite); // "It's Home, no way."
    console.log(variation.specific.titlePage); // "Welcome Haeresis"
    console.log(variation.specific.content); // "It's Home, no way."

    // We update modification here.
    next(variation);
};

en this produce the following output :

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>It's Home, no way.</title>
    </head>
    <body>
        <div class="title">It's Home, no way.</div>
        <div>
            <h1>Welcome Haeresis</h1>
            It's Home, no way.
        </div>
    </body>
</html>

If you delete the variation entry of specific page from webconfig:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json"
        }
    }
}

the output will be as following:

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Site Title</title>
    </head>
    <body>
        <div class="title">Site Title</div>
        <div>
            <h1>Welcome Haeresis</h1>
            This is a test
        </div>
    </body>
</html>

changeDom

In order to intercept DOM before it was sent, you could use common controller for all the website page and/or also a specific controller per page.

This is an example using the two hooks, the common in first and after the specific:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.js"
        }
    }
}

with this files :

├─ variations/
│  └─ index.json
├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ templates/
│  └─ index.htm
└─ webconfig.json

Do a POST request on http://localhost/ will use the following files:

variations/common.json

{
    "titleWebsite": "Site Title"
}

variations/index.json

{
    "titlePage": "Welcome",
    "content": "<p>This is Home Page.</p>"
}

templates/index.htm

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title><%- common.titleWebsite %></title>
    </head>
    <body>
        <div class="title"><%- common.titleWebsite %></div>
        <div>
            <h1><%- specific.titlePage %></h1>
            <%- specific.content %>
        </div>
    </body>
</html>

controllers/common.js

// This code is executed before DOM was sent to Client.
// This code is executed for all HTTP request, for all pages.
exports.changeDom = function (params, next) {
    var NA = this,
        dom = params.dom,
        request = params.request,
        response = params.response,
        cheerio = NA.modules.cheerio, // jsdom for manipulate DOM with jQuery.
        $ = cheerio.load(dom, { decodeEntities: false }); // We load datas for manipulate it as a DOM.

    // Just after eath h1 from HTML DOM...
    $("h1").each(function () {
        var $this = $(this);

        // ...we create a div,
        $this.after(
            // ...we inject the content of h1 into the div,
            $("<div>").html($this.html())
        );
        // ...and we delete the h1.
        $this.remove();
    });

    // We create a new HTML output with updates.
    dom = $.html();

    // We update modification here.
    next(dom);
};

controllers/index.js

// This code is executed before DOM was sent to Client.
// This code is executed only for the « / » page .
exports.changeDom = function (params, next) {
    var NA = this,
        dom = params.dom,
        request = params.request,
        response = params.response,
        cheerio = NA.modules.cheerio, // jsdom for manipulate DOM with jQuery.
        $ = cheerio.load(dom, { decodeEntities: false }); // We load datas for manipulate it as a DOM.

    // We update nodes contents with `.title` class.
    $(".title").text("Content Update");

    // We create a new HTML output with updates.
    dom = $.html();

    // We update modification here.
    next(dom);
};

the output will be as following:

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8">
        <title>Site Title</title>
    </head>
    <body>
        <div class="title">Content Update</div>
        <div>
            <div>Welcome</div>
            <p>This is Home Page.</p>
        </div>
    </body>
</html>

loadModules

To load others modules which not include into NodeAtlas, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.

This is an exemple using an external module of NodeAtlas:

{
    "commonController": "common.js",
    "routes": {
        "/": {
            "template": "index.htm",
            "controller": "index.js"
        }
    }
}

with this set of files:

├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ templates/
│  └─ index.htm
└─ webconfig.json

Do a POST request on http://localhost/ will use the following files:

templates/index.htm

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Test Module</title>
    </head>
    <body>
        <div class="title">Test Module</div>
        <div>
            <h1>Test Module</h1>
            <%- example %>
        </div>
    </body>
</html>

controllers/common.js

// This code is executing during the modules loading phase.
// This code will be executed when NodeAtlas starting.
exports.loadModules = function () {
    // Use the « NodeAtlas » instance from engine.
    var NA = this;

    // Associate each modules to allow us to use them anywhare.
    NA.modules.marked = require('marked');
};

controllers/index.js

// This code is executed before variation are injected into template engine.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
    // Use the « NodeAtlas » instance from engine.
    var NA = this,
        variation = params.variation,
        marked = NA.modules.marked;

    variation.example = marked("I am using __markdown__.");

    // We update modification here.
    next(variation);
};

this will produce the following output:

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Test Module</title>
    </head>
    <body>
        <div class="title">Test Module</div>
        <div>
            <h1>Test Module</h1>
            <p>I am using <strong>markdown</strong>.</p>
        </div>
    </body>
</html>

setConfigurations

To configure NodeAtlas web server others (ExpressJs), you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.

This is an exemple using a middleware for ExpressJs:

{
    "commonController": "common.js",
    "routes": {
        "/": {
            "template": "index.htm",
            "controller": "index.js"
        }
    }
}

with this set of files:

├─ controllers/
│  └─ common.js
├─ templates/
│  └─ index.htm
└─ webconfig.json

Do a POST request on http://localhost/ will use the following files:

templates/index.htm

<%- content %>

controllers/common.js

// This code is executing before starting of the web server.
// This code will be executed when NodeAtlas starting.
exports.setConfigurations = function (next) {
    // Use the « NodeAtlas » instance from engine.
    var NA = this;

    // Middleware utilisé lors de chaque requête.
    NA.httpServer.use(function (request, response, next) {
        response.setHeader("X-Frame-Options", "ALLOW-FROM https://www.lesieur.name/");
        next();
    });

    // We update modification here.
    next();
};

controllers/index.js

// This code is executing before starting of the web server.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
    var variation = params.variation;

    // We prepare file for JSON displaying.
    variation.currentRouteParameters.headers = {
        "Content-Type": "application/json; charset=utf-8"
    };
    variation.content = JSON.stringify(variation, null, "    ");

    // We update modification here.
    next(variation);
};

this will produce the following output:

{
    "urlBasePathSlice": "http://localhost",
    "urlBasePath": "http://localhost/",
    "urlPath": "http://localhost/",
    "pathname": /* ... */,
    "filename": /* ... */,
    "params": {},
    "currentRouteParameters": { /* ... */ },
    "currentRoute": "/",
    "webconfig": { /* ... */ }
}

setSessions

To configure client-server Sessions of NodeAtlas, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers, this is an example with Redis sessions.

This is all files for example:

├─ controllers/
│  └─ common.js
├─ templates/
│  └─ index.htm
├─ variations/
│  ├─ common.json
│  └─ index.json
└─ webconfig.json

With the webconfig.json:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json"
        }
    }
}

And "common.js" file containing e.g.:

// This code is executing during the modules loading phase.
// This code will be executed when NodeAtlas starting.
exports.loadModules = function () {
    // Find instance of « NodeAtlas » engine.
    var NA = this;

    // Associations of each module to access it anywhere.
    NA.modules.RedisStore = require('connect-redis');
};

// This code is executing while configuration of session.
// This code will be executed when NodeAtlas starting.
exports.setSessions = function (next) {
    var NA = this,
        session = NA.modules.session,
        RedisStore = NA.modules.RedisStore(session);

    // We replace the default session.
    NA.sessionStore = new RedisStore();

    // We update modification here.
    next();
};

setRoutes

To configure routes of NodeAtlas by programmation, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.

This is all files for example:

├─ controllers/
│  └─ common.js
├─ templates/
│  ├─ content.htm
│  └─ index.htm
├─ variations/
│  └─ common.json
└─ webconfig.json

With the webconfig.json:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/index.html": {
            "template": "index.htm"
        }
    }
}

And "common.js" file containing e.g.:

// This code is executing while route are added.
// This code will be executed when NodeAtlas starting.
exports.setConfigurations = function (next) {

    // We use instance of NodeAtlas.
    var NA = this,

        // And we keep routes from NodeAtlas webconfig...
        route = NA.webconfig.routes;

    // ...to add "/content.html" route amongs others routes.
    route["/content.html"] = {
        "template": "content.htm"
    };

    // We update modification here.
    next(); 
};

Use Websocket instead of AJAX

To keep a link between Front and Back part of website, NodeAtlas can use Socket.IO (more details on official website).

Thanks to this, you could change in real time data on your page, but also change data from another tabs or browsers.

With this following files:

├─ assets/
│  └─ javascript/
│     ├─ common.js
│     └─ index.js
├─ components/
│  ├─ foot.htm
│  ├─ head.htm
│  └─ index.htm
├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ variations/
│  ├─ common.json
│  └─ index.json
├─ templates/
│  └─ index.htm
└─ webconfig.json

With this webconfig.json:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.js"
        }
    }
}

and with this templates files:

components/head.htm

<!DOCTYPE html>
<html lang="<%= languageCode %>">
    <head>
        <meta charset="utf-8" />
        <title><%- common.titleWebsite %></title>
    </head>
    <body data-hostname="<%= webconfig.urlWithoutFileName %>" data-subpath="<%= webconfig.urlRelativeSubPath.slice(1) %>" data-variation="<%= currentRouteParameters.variation.replace(/\.json/,'') %>">

Note : data-hostname and data-subpath will help us to set Socket.IO front configuration.

components/foot.htm

        <script type="text/javascript" src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
        <script src="javascript/common.js"></script>
    </body>
</html>

Note : The Front file of Socket.IO is calling here.

components/index.htm

        <div class="title"><%- common.titleWebsite %></div>
        <div>
            <h1><%- specific.titlePage %></h1>
            <%- specific.content %>
            <div><%- new Date() %></div>
        </div>
        <button>Update</button>

Note : Each click on button will update content from components/index.htm.

templates/index.htm

    <%- include('head.htm') %>
    <div class="layout">
    <%- include('index.htm') %>
    </div>
    <script src="javascript/index.js"></script>
    <%- include('foot.htm') %>

Note : We parse here the home page /.

and the following variations files :

variations/common.json

{
    "titleWebsite": "Socket.IO Example"
}

variations/index.json

{
    "titlePage": "Date",
    "content": "<p>Current date is:</p>"
}

All work fine here, but see what we will do with controller part on Server-side and on Client-side.

On server, we will use the following files:

controllers/common.js

var privates = {};

// Load modules for this site in the NodeAtlas object.
exports.loadModules = function () {
    // Find instance of « NodeAtlas » engine.
    var NA = this;

    // Associations of each module to access it anywhere.
    NA.modules.socketio = require('socket.io');
    NA.modules.cookie = require('cookie');
};

// Example using Socket.IO.
privates.socketIoInitialisation = function (socketio, NA, next) {
    var optionIo = (NA.webconfig.urlRelativeSubPath) ? { path: NA.webconfig.urlRelativeSubPath + '/socket.io', secure: ((NA.webconfig.httpSecure) ? true : false) } : undefined,
        io = socketio(NA.server, optionIo),
        cookie = NA.modules.cookie,
        cookieParser = NA.modules.cookieParser;

    // Synchronizing sessions with Socket.IO.
    io.use(function(socket, next) {
        var handshakeData = socket.request;

        // Fallback if cookies are not supported.
        if (!handshakeData.headers.cookie) {
            return next(new Error('Session cookie required.'));
        }

        // Transformation of the cookie String to JSON object.
        handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);

        // Verification of the signature of the cookie.
        handshakeData.cookie = cookieParser.signedCookies(handshakeData.cookie, NA.webconfig.session.secret);

        // Keep worn the Session ID.
        handshakeData.sessionID = handshakeData.cookie[NA.webconfig.session.key];

        // Accept the cookie.
        NA.sessionStore.load(handshakeData.sessionID, function (error, session) {
            if (error || !session) {
                return next(new Error('No recovered session.'));
            } else {
                handshakeData.session = session;
                next();
            }
        });
    });

    // Next.
    next(io);
};

// Adding listener for a specific controller "index.js" (see example in the next file).
privates.socketIoEvents = function (io, NA) {
    var params = {};

    params.io = io;

    // Event for the index page (see example in the next file).
    require('./index').asynchrone.call(NA, params);
};

// Configuration of all modules.
exports.setConfigurations = function (next) {
    var NA = this,
        socketio = NA.modules.socketio;

    // Initialize Socket IO.
    privates.socketIoInitialisation(socketio, NA, function (io) {

        // Socket IO listening.
        privates.socketIoEvents(io, NA);

        // Next steps of engine.
        next();
    });
};

Note : This is Socket.IO server global configuration.

controllers/index.js

// All Websocket action possible for this template.
// Used not by "NodeAtlas" but with "common.js" (see previous file).
exports.asynchrone = function (params) {
    var NA = this,
        io = params.io;

    // Once we have a valid connection between the client and our back-end...
    io.sockets.on('connection', function (socket) {

        // ...stay tuned on the "create-item-button" demand...
        socket.on("server-render", function (data) {
            var sessionID = socket.request.sessionID,
                session = socket.request.session,
                variation = {};

            // Specific variations in the good language.
            variation = NA.addSpecificVariation("index.json", data.lang, variation);

            // Common variations in the good language.
            variation = NA.addCommonVariation(data.lang, variation);

            // HTML part from `componentsRelativePath` directory and render with variations.
            result = NA.newRender("index.htm", variation);

            // And responds to all customers with a set of data in data.
            io.sockets.emit('create-article-button', data);
        });
    });
};

And for client-side, we use the following files:

assets/javascript/common.js

window.website = window.website || {};

(function (publics) {
    "use strict";

    var privates = {},
        optionsSocket,
        body = document.getElementsByTagName("body")[0];

    // We configure Socket.IO client-side.
    optionsSocket = (body.getAttribute("data-subpath") !== "") ? { path: "/" + body.getAttribute("data-subpath") + ((body.getAttribute("data-subpath")) ? "/" : "") + "socket.io" } : undefined;
    publics.socket = io.connect((body.getAttribute("data-subpath") !== "") ? body.getAttribute("data-hostname") : undefined, optionsSocket);
}(website));

// We execute specific JavaScript, here it's ["index"].
website[document.getElementsByTagName("body")[0].getAttribute("data-variation")].init();

Note : This is the global Socket.IO configuration client-side with data-subpath and data-hostname.

assets/javascript/index.js

window.website = window.website || {};

(function (publics) {
    "use strict";

    var html = document.getElementsByTagName("html")[0],
        body = document.getElementsByTagName("body")[0],
        layout = document.getElementsByClassName("layout")[0];

    // We associate on the button the action to contact server.
    function setServerRender() {
        var button = document.getElementsByTagName("button")[0];
        button.addEventListener("click", function () {
            website.socket.emit("server-render", {
                lang: html.getAttribute("lang"),
                variation: body.getAttribute("data-variation")
            });
        });
    }

    // We create the code will be executed when page run.
    publics.init = function () {

        // We set action on button.
        setServerRender();

        // When server response come back...
        website.socket.on("server-render", function (data) {

            // ...we update data content...
            layout.innerHTML = data.render;

            // ...and we set again button action.
            setServerRender();
        });
    };
}(website.index = {}));

Run your project and go on http://localhost/ across multiple tab and/or multiple browser. You will see when you click on « Update », the page (current date) will be updated on all tabs open.

Thanks to NA.addSpecificVariation, NA.addCommonVariation and NA.newRender, it's possible to generate a new template and variation compilation.

If data.lang in this example is type of undefined, files will be search in rood directory. If currentVariation is type of undefined an empty object will be created.

Use MySQL Database (SQL)

We will see now how to use data from database. We will use the mysql npm module. And first, install a MySQL server.

MySQL Database

First, we will create a database demo on the server:

CREATE DATABASE demo;

and select it:

USE demo

and create a user table:

CREATE TABLE user
(
    id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    lastname VARCHAR(100),
    firstname VARCHAR(100),
    email VARCHAR(255),
    birthdate DATE,
    gender TINYINT(1),
    country VARCHAR(255),
    town VARCHAR(255),
    zipcode VARCHAR(5),
    address VARCHAR(255)
);

and fill it with this set of data:

INSERT INTO user (
    lastname,
    firstname,
    email,
    birthdate,
    gender,
    country,
    town,
    zipcode,
    address
) VALUES (
    "Lesieur",
    "Bruno",
    "bruno.lesieur@gmail.com",
    "1988/07/18",
    true,
    "France",
    "Annecy",
    74000,
    "66 avenue de Genève"
);

NodeAtlas Files

With the following data set:

├─ assets/
│  └─ javascript/
│     └─ models/
│        └─ user.js
├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ models/
│  └─ user.js
├─ templates/
│  └─ index.htm
├─ variations/
│  ├─ common.json
│  └─ index.json
└─ webconfig.json

We will use the following webconfig.json with the custom _mysqlConfig variable which contain all informations for database connection:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.js"
        }
    },
    "_mysqlConfig": {
        "host": "localhost",
        "user": "root",
        "password": "root",
        "database": "demo"
    }
}

With following files to display page:

templates/index.htm

<!DOCTYPE html>
<html lang="<%- languageCode %>">
    <head>
        <meta charset="utf-8" />
        <title><%- common.titleWebsite %></title>
    </head>
    <body>
        <div class="title"><%- common.titleWebsite %></div>
        <div>
            <h1><%- specific.titlePage %></h1>
            <%- specific.content %>
            <ul>
                <li>Id: <strong><%- id %></strong></li>
                <li>Lastname: <strong><%- lastname %></strong></li>
                <li>Firstname: <strong><%- firstname %></strong></li>
                <li>Email: <strong><%- email %></strong></li>
                <li>Birthdate: <strong><%- birthdate %></strong></li>
                <li>Gender: <strong><%- gender %></strong></li>
                <li>Country: <strong><%- country %></strong></li>
                <li>Town: <strong><%- town %></strong></li>
                <li>Zipcode: <strong><%- zipcode %></strong></li>
                <li>Address: <strong><%- address %></strong></li>
            </ul>
        </div>
    </body>
</html>

variations/common.json

{
    "titleWebsite": "Example MySql",
    "male": "Man",
    "female": "Woman"
}

variations/index.json

{
    "titlePage": "User Table",
    "content": "<p>`bruno` entry details.</p>"
}

And last, we will be connect to the database with the common controller controllers/common.js:

exports.loadModules = function () {
    var NA = this;

    NA.modules.mysql = require('mysql');
    NA.models = {};
    NA.models.User = require('../models/user.js');
};

exports.setConfigurations = function (next) {
    var NA = this,
        mysql = NA.modules.mysql;

    NA.mySql = mysql.createPool(NA.webconfig._mysqlConfig);

    next();
};

And display result via specific controller controllers/index.js:

exports.changeVariation = function (params, next) {
    var NA = this,
        variation = params.variation,
        User = NA.models.User,
        bruno = User();

    NA.mySql.getConnection(function(err, connection) {
        if (err) {
            console.log(err);
            return false;
        }

        bruno
        .setConnection(connection)
        .firstname("bruno")
        .readFirst(function () {

            variation.id = bruno.id();
            variation.lastname = bruno.lastname();
            variation.firstname = bruno.firstname();
            variation.email = bruno.email();
            variation.birthdate = bruno.birthdate();
            variation.gender = (bruno.gender()) ? variation.common.male : variation.common.female;
            variation.country = bruno.country();
            variation.town = bruno.town();
            variation.zipcode = bruno.zipcode();
            variation.address = bruno.address();

            next(variation);
        });
    });
};

with the user model via connect file to database models/user.js:

/* jslint esversion: 6 */
var user = require('../assets/javascript/models/user.js');

function User(connection) {
    var privates = {},
        publics = this;

    privates.connection = connection;

    if (!(publics instanceof User)) {
        return new User();
    }

    publics.setConnection = function (connection) {
        privates.connection = connection;
        return publics;
    };

    user.call(publics);

    publics.readFirst = function (callback) {
        var select = `SELECT
                    id,
                    lastname,
                    firstname,
                    email,
                    birthdate,
                    gender,
                    country,
                    town,
                    zipcode,
                    address
                FROM user`, 
            where = "", 
            limit = " LIMIT 0,1 ",
            addWhere = " WHERE ";

        if (publics.id()) { where += addWhere + "`id` = '" + publics.id().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.lastname()) { where += addWhere + "`lastname` = '" + publics.lastname().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.firstname()) { where += addWhere + "`firstname` = '" + publics.firstname().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.email()) { where += addWhere + "`email` = '" + publics.email().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.birthdate()) { where += addWhere + "`birthdate` = '" + publics.birthdate().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.gender()) { where += addWhere + "`gender` = '" + publics.gender().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.country()) { where += addWhere + "`country` = '" + publics.country().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.town()) { where += addWhere + "`town` = '" + publics.town().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.zipcode()) { where += addWhere + "`zipcode` = '" + publics.zipcode().replace(/'/g, "''") + "'"; addWhere = ' && '; }
        if (publics.address()) { where += addWhere + "`address` = '" + publics.address().replace(/'/g, "''") + "'"; addWhere = ' && '; }

        privates.connection.query(select + where + limit, function(err, rows, fields) {
            if (err) console.log(err);

            if (rows[0]) {
                publics.id(rows[0].id);
                publics.lastname(rows[0].lastname);
                publics.firstname(rows[0].firstname);
                publics.email(rows[0].email);
                publics.birthdate(rows[0].birthdate);
                publics.gender((rows[0].gender) ? true : false);
                publics.country(rows[0].country);
                publics.town(rows[0].town);
                publics.zipcode(rows[0].zipcode);
                publics.address(rows[0].address);
            }

            callback();
        });
    };
}

User.prototype = Object.create(user.prototype);
User.prototype.constructor = User;

module.exports = User;

based on user classe shared between Front and Back part assets/javascript/models/user.js:

(function (expose, factory) {
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = factory;
    } else {
        expose.User = factory;
    }
}(this, function User() {
    var privates = {},
        publics = this;

    if (!(publics instanceof User)) {
        return new User();
    }

    publics.id = function (id) {
        if (typeof id === 'undefined') {
            return privates.id;
        } else {
            privates.id = id;
            return publics;
        }
    };

    publics.lastname = function (lastname) {
        if (typeof lastname === 'undefined') {
            return privates.lastname;
        } else {
            privates.lastname = lastname;
            return publics;
        }
    };

    publics.firstname = function (firstname) {
        if (typeof firstname === 'undefined') {
            return privates.firstname;
        } else {
            privates.firstname = firstname;
            return publics;
        }
    };

    publics.email = function (email) {
        if (typeof email === 'undefined') {
            return privates.email;
        } else {
            privates.email = email;
            return publics;
        }
    };

    publics.birthdate = function (birthdate) {
        if (typeof birthdate === 'undefined') {
            return privates.birthdate;
        } else {
            privates.birthdate = birthdate;
            return publics;
        }
    };

    publics.gender = function (gender) {
        if (typeof gender === 'undefined') {
            return privates.gender;
        } else {
            privates.gender = gender;
            return publics;
        }
    };

    publics.country = function (country) {
        if (typeof country === 'undefined') {
            return privates.country;
        } else {
            privates.country = country;
            return publics;
        }
    };

    publics.town = function (town) {
        if (typeof town === 'undefined') {
            return privates.town;
        } else {
            privates.town = town;
            return publics;
        }
    };

    publics.zipcode = function (zipcode) {
        if (typeof zipcode === 'undefined') {
            return privates.zipcode;
        } else {
            privates.zipcode = zipcode;
            return publics;
        }
    };

    publics.address = function (address) {
        if (typeof address === 'undefined') {
            return privates.address;
        } else {
            privates.address = address;
            return publics;
        }
    };
}));

You will get the following output:

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="utf-8" />
        <title>MySql Example</title>
    </head>
    <body>
        <div class="title">MySql Example</div>
        <div>
            <h1>User Table</h1>
            <p>`bruno` entry details.</p>
            <ul>
                <li>Id: <strong>1</strong></li>
                <li>Lastname: <strong>Lesieur</strong></li>
                <li>Firstname: <strong>Bruno</strong></li>
                <li>Email: <strong>bruno.lesieur@gmail.com</strong></li>
                <li>Birthdate: <strong>Mon Jul 18 1988 00:00:00 GMT+0200 (Paris, Madrid (heure d’été))</strong></li>
                <li>Gender: <strong>Homme</strong></li>
                <li>Country: <strong>France</strong></li>
                <li>Town: <strong>Annecy</strong></li>
                <li>Zipcode: <strong>74000</strong></li>
                <li>Address: <strong>66 avenue de Genève</strong></li>
            </ul>
        </div>
    </body>
</html>

Use MongoDB Database (NoSQL)

We will see now how to use data from nosql database. We will use the mongoose npm module. And first, install a MongoDB server.

MongoDB Database

First, we will create a database demo on the server and select it:

use demo

and create a user collection:

db.createCollection("user")

and fill it with this document:

db.user.insert({
    email: "bruno.lesieur@gmail.com",
    identity: {
        lastname: "Lesieur",
        firstname: "Bruno",
        gender: true,
        birthdate : new Date("1988/07/18")
    },
    location: {
        country: "France",
        town: "Annecy",
        zipcode: "74000",
        address: "66 avenue de Genève"
    }
})

NodeAtlas Files

With the following data set:

├─ assets/
│  └─ javascript/
│     └─ models/
│        └─ user.js
├─ controllers/
│  ├─ common.js
│  └─ index.js
├─ templates/
│  └─ index.htm
├─ variations/
│  ├─ common.json
│  └─ index.json
└─ webconfig.json

We will use the following webconfig.json with the custom _mongodbConfig variable which contain all informations for database connection:

{
    "commonController": "common.js",
    "commonVariation": "common.json",
    "routes": {
        "/": {
            "template": "index.htm",
            "variation": "index.json",
            "controller": "index.js"
        }
    },
    "_mongodbConfig": {
        "host": "localhost",
        "port": "27017",
        "database": "demo"
    }
}

With following files to display page:

templates/index.htm

<!DOCTYPE html>
<html lang="<%- languageCode %>">
    <head>
        <meta charset="utf-8" />
        <title><%- common.titleWebsite %></title>
    </head>
    <body>
        <div class="title"><%- common.titleWebsite %></div>
        <div>
            <h1><%- specific.titlePage %></h1>
            <%- specific.content %>
            <ul>
                <li>Id: <strong><%- id %></strong></li>
                <li>Lastname: <strong><%- lastname %></strong></li>
                <li>Firstname: <strong><%- firstname %></strong></li>
                <li>Email: <strong><%- email %></strong></li>
                <li>Birthdate: <strong><%- birthdate %></strong></li>
                <li>Gender: <strong><%- gender %></strong></li>
                <li>Country: <strong><%- country %></strong></li>
                <li>Town: <strong><%- town %></strong></li>
                <li>Zipcode: <strong><%- zipcode %></strong></li>
                <li>Address: <strong><%- address %></strong></li>
            </ul>
        </div>
    </body>
</html>

variations/common.json

{
    "titleWebsite": "Example MongoDB",
    "male": "Man",
    "female": "Woman"
}

variations/index.json

{
    "titlePage": "User Collection",
    "content": "<p>Document `{ \"identity.firstname\": \"Bruno\" }` details.</p>"
}

And last, we will be connect to the database with the common controller controllers/common.js:

exports.loadModules = function () {
    var NA = this,
        path = NA.modules.path;

    NA.modules.mongoose = require('mongoose');
    NA.models = {};
    NA.models.User = require('../assets/javascript/models/user.js');
};

exports.setConfigurations = function (next) {
    var NA = this,
        mongoose = NA.modules.mongoose,
        config = NA.webconfig._mongodbConfig;

    mongoose.Promise = global.Promise;
    mongoose.model("user", NA.models.User, "user");
    mongoose.connect("mongodb://" + config.host + ":" + config.port + "/" + config.database, function (error) {
        next();
    });
};

And display result via specific controller controllers/index.js:

exports.changeVariation = function (params, next) {
    var NA = this,
        variation = params.variation,
        mongoose = NA.modules.mongoose,
        User = mongoose.model('user');

    User
    .findOne({ "identity.firstname": "Bruno" })
    .exec(function (err, bruno) {

        variation.id = bruno._id;
        variation.lastname = bruno.identity.lastname;
        variation.firstname = bruno.identity.firstname;
        variation.birthdate = bruno.identity.birthdate;
        variation.email = bruno.email;
        variation.gender = (bruno.identity.gender) ? variation.common.male : variation.common.female;
        variation.country = bruno.location.country;
        variation.town = bruno.location.town;
        variation.zipcode = bruno.location.zipcode;
        variation.address = bruno.location.address;

        next(variation);
    });
};

based on user classe shared between Front and Back part assets/javascript/models/user.js:

var mongoose;
if (typeof module !== 'undefined' && module.exports) {
     mongoose = require('mongoose');
}

(function (expose, factory) {
    if (mongoose) {
        module.exports = factory;
    } else {
        expose.User = factory;
    }
}(this, new mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    email: { type : String, match: /^\S+@\S+$/ },
    identity: {
        lastname: String,
        firstname: String,
        gender: Boolean,
        birthdate : { type : Date, default : Date.now }
    },
    location: {
        country: String,
        town: String,
        zipcode: String,
        address: String
    }
})));

You will get the following output:

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="utf-8" />
        <title>MongoDB Example</title>
    </head>
    <body>
        <div class="title">MongoDB Example</div>
        <div>
            <h1>User Collection</h1>
            <p>Collection `{ "identity.firstname": "Bruno" }` details.</p>
            <ul>
                <li>Id: <strong>1</strong></li>
                <li>Lastname: <strong>Lesieur</strong></li>
                <li>Firstname: <strong>Bruno</strong></li>
                <li>Email: <strong>bruno.lesieur@gmail.com</strong></li>
                <li>Birthdate: <strong>Mon Jul 18 1988 00:00:00 GMT+0200 (Paris, Madrid (heure d’été))</strong></li>
                <li>Gender: <strong>Homme</strong></li>
                <li>Country: <strong>France</strong></li>
                <li>Town: <strong>Annecy</strong></li>
                <li>Zipcode: <strong>74000</strong></li>
                <li>Address: <strong>66 avenue de Genève</strong></li>
            </ul>
        </div>
    </body>
</html>