Code Explanation - S4

Let's explore the config and index files of S4.

config.js
'use strict';

module.exports = {
   type: 'service',
   prerequisites: {
      cpu: '',
      memory: ''
   },
   serviceVersion: 1,
    serviceName: "jsconf4",
    serviceGroup: "JSConf",
    servicePort: 4114,
    requestTimeout: 30,
    requestTimeoutRenewal: 5,
    extKeyRequired: true,
    "errors": {
       600: "Database Error"
    },
    "schema": {
       "/standalone/add": {
          "_apiInfo":{
             "l": "Add Info to Standalone DB",
             "group": "Information",
             "groupMain": true
          },
          "username": {
             "source": ['body.username'],
             "required": true,
             "validation": {
                "type": "string",
                "minLength": 4,
                "maxLength": 8,
                "pattern": /^[a-zA-Z][0-9a-zA-Z_\-]+$/
             }
          },
          "name": {
             "source": ['body.name'],
             "required": false,
             "default": "anonymous",
             "validation": {
                "type": "string"
             }
          },
          "email": {
             "source": ['body.email'],
             "required": true,
             "validation": {
                "type": "array",
                "items": {
                   "type": "object",
                   "properties": {
                      "address": {"type": "string", "format": "email", "required": true},
                      "primary": {"type": "boolean", "required": true}
                   }
                },
                "minItems": 1,
                "maxItems": 5,
                "uniqueItems": true
             }
          }
       },
       "/multi/add": {
          "_apiInfo":{
             "l": "Add Info in Multitenant DB",
             "group": "Information",
             "groupMain": true
          },
          "username": {
             "source": ['body.username'],
             "required": true,
             "validation": {
                "type": "string",
                "minLength": 4,
                "maxLength": 8,
                "pattern": /^[a-zA-Z][0-9a-zA-Z_\-]+$/
             }
          },
          "name": {
             "source": ['body.name'],
             "required": false,
             "default": "anonymous",
             "validation": {
                "type": "string"
             }
          },
          "email": {
             "source": ['body.email'],
             "required": true,
             "validation": {
                "type": "array",
                "items": {
                   "type": "object",
                   "properties": {
                      "address": {"type": "string", "format": "email", "required": true},
                      "primary": {"type": "boolean", "required": true}
                   }
                },
                "minItems": 1,
                "maxItems": 5,
                "uniqueItems": true
             }
          }
       },
       "/hybrid": {
          "_apiInfo":{
             "l": "Hybrid API",
             "group": "Information",
             "groupMain": true
          },
          "name": {
             "source": ['body.name'],
             "required": false,
             "validation": {
                "type": "string"
             }
          }
       }
    }
};

The config file looks pretty similar to what we have seen before, however notice that we have added a new route, /hybrid.

index.js
'use strict';
var soajs = require('soajs');
var config = require('./config.js');
var jsconfSRV = new soajs.server.service(config);

/**
 * Declare a global variable, usage is below
 */
var myMongo;

jsconfSRV.init(function () {

   jsconfSRV.post("/standalone/add", function(req, res){

      if(!myMongo){
         /**
          * Initializing DB Connection
          */
         req.soajs.log.debug("Creating new DB connection to users database.");
         var dbConfiguration = req.soajs.registry.coreDB.myDatabase;
         myMongo = new soajs.mongo(dbConfiguration);
      }
      else{
         req.soajs.log.debug("Mongo Instance already created, reusing existing connection.");
      }

      /**
       * Formulating Document to insert
       */
      req.soajs.log.debug("Formulating new record: " + JSON.stringify(req.soajs.data));
      var record = {
         'username': req.soajs.inputmaskData.username,
         'name': req.soajs.inputmaskData.name,
         'email': req.soajs.inputmaskData.email
      };

      myMongo.insert("data", record, true, function (error) {
         if (error) {
            req.soajs.log.error(error);
            return res.jsonp(req.soajs.buildResponse({'code': 600, 'msg': config.errors[600]}));
         }

         return res.json(req.soajs.buildResponse(null, true));
      });
   });

   jsconfSRV.post("/multi/add", [
      function (req, res, next) {
         /**
          * Initializing DB Connection
          */
         req.soajs.log.debug("Creating new DB connection to users database.");
         var dbConfiguration = req.soajs.meta.tenantDB(req.soajs.registry.tenantMetaDB, "users", req.soajs.tenant.code);
         req.soajs.mongo = new soajs.mongo(dbConfiguration);

         /**
          * Formulating Document to insert, push to request, will use it in next mw
          */
         req.soajs.log.debug("Formulating new record: " + JSON.stringify(req.soajs.data));
         req.soajs.data = {
            'username': req.soajs.inputmaskData.username,
            'name': req.soajs.inputmaskData.name,
            'email': req.soajs.inputmaskData.email
         };
         next();

      },
      function (req, res) {

         /**
          * Inserting Document in DB
          */
         req.soajs.mongo.insert("data", req.soajs.data, true, function (error) {
            req.soajs.mongo.closeDb();
            if (error) {
               req.soajs.log.error(error);
               return res.jsonp(req.soajs.buildResponse({'code': 600, 'msg': config.errors[600]}));
            }

            return res.json(req.soajs.buildResponse(null, true));
         });
      }
   ]);

   jsconfSRV.get("/hybrid", function (req, res) {

      var data;
      var tenantConfig = req.soajs.servicesConfig;
      switch(tenantConfig.style){
         case 'simple':
            data = "Hello i am a message!";
            break;
         case 'advanced':
            data = tenantConfig.obj.name.replace("%name%", req.soajs.inputmaskData.name);
            break;
         case 'imfv':
            data = {};
            data.name = tenantConfig.obj.name.replace("%name%", req.soajs.inputmaskData.name);
            data.email = tenantConfig.obj.email.replace("%email%", req.soajs.inputmaskData.name);
            break;
      }


      return res.json(req.soajs.buildResponse(null, data));
   });

   jsconfSRV.start();
});

The index file of S4 is quite different from the previous examples. 

Here we see a new API that allows different tenants access to Mongo.

How does SOAJS achieve this?

When creating the Mongo connector, SOAJS takes into account the tenant code. This means that there is a Mongo connector created for every tenant accessing the database.

Finally, let's look at the hybrid API:

SOAJS gives developers the power to make one API respond in different ways according to which tenant is calling it.

If we look at the code, we can see the variable "tenantConfig". This variable is what differentiates the various tenants from one another. 

In this case, we are creating a switch-case block that binds different objects to the "data" variable, based on which tenant is calling the API.