# node-base-module

![RankingCoach](https://www.rankingcoach.com/jump/img/public/rC_logo.svg)

Typescript bundle with usefull & easy to use sub-modules
# Installation
This is a [Typescript/Node.js](https://nodejs.org/en/) module available via [npm](https://www.npmjs.com/).
Before installing, [download and install Node.js](https://nodejs.org/en/download/). Node.js 6.9.5 or higher is required.
Installation is done using the [npm install command:](https://docs.npmjs.com/getting-started/installing-npm-packages-locally)
```sh
$ npm install --save node-base-module
```

# Description
This module allow you to start from an express server which includes:
-   Access logger middleware using [morgan](https://www.npmjs.com/package/morgan) for formating and [rotating-file-stream](https://www.npmjs.com/package/rotating-file-stream) for rotating files/compress
-   [swagger-jsdoc](https://www.npmjs.com/package/swagger-jsdoc) accessible through "\swagger.json" with autorization check
-   A health route "\health" to check your project health
-   A prometeus route "\metrics" to get project informations

    
Also include an easy way to manage multiple connections for:
-   Redis using [ioredis](https://www.npmjs.com/package/ioredis)
-   Elasticsearch using [elasticsearch](https://www.npmjs.com/package/elasticsearch)
-   Cassandra using [cassandra-driver](https://www.npmjs.com/package/cassandra-driver)
-   Mailer using [nodemailer](https://www.npmjs.com/package/nodemailer)
-   Mysql using [mysql](https://www.npmjs.com/package/mysql)
-   Inner logger
-   Multiple registries of Prometeus
    
Extra
-   Inner crashreporter with e-mail support using [nodemailer](https://www.npmjs.com/package/nodemailer)
-   [nock](https://www.npmjs.com/package/nock)
-   [mocha](https://www.npmjs.com/package/mocha)
    
# Configuration
All default configuration can be found in "options.json"
To overwrite it partialy or entirely use:
```js
var base = require('node-base-module')
base.setDefaultOptions({
    "swagger": {
        "swaggerDefinition": {
            "info": {
                "title": "Exemple base module",
                "version": "1.0.0",
                "description": "Base module for all node.js projects"
            },
        },
    }
});
```
or you can specify an extern file to get setting from:
```js
base.setDefaultFileOptions("./options.json");
```
this function returns a boolean which indicates if the settings were loaded successfully.

# Create a WebServer
To create a new WebServer you need two steps:

```js
const base = require('node-base-module');
//Step 1
var express = base.express();
//Step 2
this.app = express.initialize();
```
### Example
```js
/**
*web-server.js
*/
let base = require('node-base-module');

class SimpleWebServer {
    public app;    
    public server;

    constructor() {
        
        //Configurate the WebServer
        base.setDefaultOptions({
            "swagger": {
                "apis": ["./web-server.js"],
                "allowedDomains": ["localhost"]
            }
        });


        /**
         * Get your own express web server uninitiated
         */
        var express = base.express();

        /**
         * Generate an express client
         */
        this.app = express.initialize();

        /**
         * Include routes (with swagger documentation)
         */

         /**
          * @swagger
          * /test:
          *   get:
          *     summary: Get
          *     description:
          *       "Make test request"
          *     tags:
          *       - Comands
          *     produces:
          *         - "application/json"
          *     responses:
          *       200:
          *         description: OK
          */
        this.app.get('/test', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            res.status(200);                    
            res.send(JSON.stringify({response:"Our test response"})); 
        });

        /**
         * Public your webserver
         */
        let port = 9876;
        this.server = this.app.listen(port);
    }
}
new SimpleWebServer();
```
Beside "/test" route, "/swagger.json" (swagger documentation) and "/health" ( health check) were automatically created.

You can find more example included in the module at "src/demo"

# Connection pool
-   The module includes a connection pool build-in feature, which is applyed to our already supported connections:
-       redis
-       elastic
-       cassandra
-       mysql
-       mailer
-       even logger which is not really an external connection
-   This feature is exported and can be used to also hold your own connections


### Default connection
How to use global connection:
```js
var base = require('node-base-module');
base.redis(); //For redis
base.cassandra(); //For cassandra
base.mysql(); //For mysql
base.elastic(); //For elasticsearch
base.logger(); //For logger
base.mailer(); //For mailer
```
When you use this for first time the module will automaticaly create a new default one based on your default configuration:
 ```js
 var base = require('node-base-module');
 base.setDefaultOptions({});
 ```
 
 If you want to set new settings just for default connection without affecting default setting you can use:
```js
var base = require('node-base-module');
base.redis.configurate({}); //For redis
base.cassandra.configurate({}); //For cassandra
base.elastic.configurate({}); //For elasticsearch
base.mysql.configurate({}); //For mysql
base.logger.configurate({}); //For logger
base.mailer.configurate({}); //For mailer
```
You can overwrite settings partialy (missing settings will be filled from default settings) or entirely.
If you change configuration after connection was use, module will close old connection and create a new one using the new configuration.

### Create multiple connections
To create a new custom connection you need to specific which settings differ from default setting and an unique tag to be able to difference connections
##### Exemple
```js
var base = require('node-base-module');
base.redis.newInstance({
    "port": 6380,
    "host": "localhost",
}, "unique_tag");
```
##### Usage:
```js
var base = require('node-base-module');
base.redis.newInstance({}, "unique_tag"); //For redis
base.cassandra.newInstance({}, "unique_tag"); //For cassandra
base.mysql.newInstance({}, "unique_tag"); //For mysql
base.elastic.newInstance({}, "unique_tag"); //For elasticsearch
base.logger.newInstance({}, "unique_tag"); //For logger
base.mailer.newInstance({}, "unique_tag"); //For mailer
```
To use the new connection you don't need to keep a reference to the connection, just get the connection you want using the unique tag.
```js
var base = require('node-base-module');
base.redis("unique_tag"); //For redis
base.cassandra("unique_tag"); //For cassandra
base.elastic("unique_tag"); //For elasticsearch
base.mysql("unique_tag"); //For mysql
base.logger("unique_tag"); //For logger
base.mailer("unique_tag"); //For mailer
```

### Delete a connection
To delete a connection you need only the unique tag
```js
var base = require('node-base-module');
base.redis.deleteInstance("unique_tag"); //For redis
base.cassandra.deleteInstance("unique_tag"); //For cassandra
base.elastic.deleteInstance("unique_tag"); //For elasticsearch
base.mysql.deleteInstance("unique_tag"); //For mysql
base.logger.deleteInstance("unique_tag"); //For logger
base.mailer.deleteInstance("unique_tag"); //For mailer
```

You can also delete global/default connection if you dont have anymore need of it, using:
```js
var base = require('node-base-module');
base.redis.deleteInstance(); //For redis
base.cassandra.deleteInstance(); //For cassandra
base.elastic.deleteInstance(); //For elasticsearch
base.mysql.deleteInstance(); //For mysql
base.logger.deleteInstance(); //For logger
base.mailer.deleteInstance(); //For mailer
```
or
```js
var base = require('node-base-module');
base.redis.deleteInstance("global"); //For redis
base.cassandra.deleteInstance("global"); //For cassandra
base.elastic.deleteInstance("global"); //For elasticsearch
base.mysql.deleteInstance("global"); //For mysql
base.logger.deleteInstance("global"); //For logger
base.mailer.deleteInstance("global"); //For mailer
```
You don't need to close a connection before overwrite it or change the parameters, module will always close connections before discard it.

# /health
If your project depents on extra connections or resources outside the module, you can add those dependencies in the "/health" route check, using:
```js
var base = require('node-base-module');
base.setProjectFunctionality(function(){
            return true; //return true if all is functional or false otherwise
        });
```
and for status use:
```js
var base = require('node-base-module');
base.setProjectStatus(function(){
            return {
                "resource": "status"
            };
        });
```

Also if you want to check in code if all is functional, use:
```js
var base = require('node-base-module');
base.isFunctional();
```

#   Crashreporter
How to use crashreporter:
```js
var base = require('node-base-module');
base.crashreporter();
```
Crashreporter will use default settings unless a set of crashreporter settings are specified.
```js
var base = require('node-base-module');
base.crashreporter({
    "mailSubject": "New maill subject"
});
```

#    Metrics
To manage multiple registries:
```js
base.metrics(); //To access default registry
base.metrics.newInstance("name"); // To create new registry
base.metrics("name"); //To access custom registry
base.metrics.deleteInstance("name"); //To delete a registry
```

You can manage a registry using:
```js
/**
 * To delete all metrics from a registry
 */
base.metrics().destroy();

/**
 * Get string representation for all metrics
 */
base.metrics().metrics();

/**
 * Reset all metrics in the registry
 */
base.metrics().resetMetrics();

/**
 * Get all metrics as objects
 */
base.metrics().getMetricsAsJSON();

/**
 * Set static labels to every metric emitted by this registry
 * @param labels of name/value pairs:
 * { defaultLabel: "value", anotherLabel: "value 2" }
 */
base.metrics().setDefaultLabels();

/**
 * Get the Content-Type of the metrics for use in the response headers.
 */
base.metrics().contentType;
```
We support 3 type of metrics: counter, gauge, history
Gauge supports an aggregation parameter
You can use multiple types.
All suported types are:
```js
this.base.AGGREGATORS.MIN
this.base.AGGREGATORS.AVERAGE
this.base.AGGREGATORS.MAX;
```

For metric management use:
```js
let aggregators = this.base.AGGREGATORS.MIN | this.base.AGGREGATORS.AVERAGE | this.base.AGGREGATORS.MAX;

/**
 * To create a new metric in some registry can use:
 */
this.base.metrics().newCounter("name", "description", ["labels"]);
this.base.metrics().newGauge("name", "description", ["labels"], aggregators); // Just Gauge support aggregators
this.base.metrics().newHistogram("name", "description", ["labels"]);

/**
 * Use some metric from a registry can use:
 */
this.base.metrics().counter("name");  
this.base.metrics().gauge("name");
this.base.metrics().histogram("name");

/**
 * Delete some metric from a registry can use:
 */
this.base.metrics().deleteCounter("name");  
this.base.metrics().deleteGauge("name");
this.base.metrics().deleteHistogram("name");
```
#    Consul
To manage multiple instance:
```js
base.consul(); //To access default consul instance
base.consul.newInstance("name"); // To create new consul instance
base.consul("name"); //To access custom consul instance
base.consul.deleteInstance("name"); //To delete a consul instance
```

Each consul can observe multiple services:
To create a new observer use newObserver method on your consul instance.
Each consul instance represent a different consul connection
```js
/**
 * To create new Observer
 */
base.consul().newObserver("service name");
/**
* newObserver() always return an observer instance
* if do not exist an observer for that service a new observer will be created
* else will be returned the old one and a message will be sent using second 
* paramerter which is optional
*/

/**
 * Get an observer for sone service
 */
base.consul().observer("service name");
/**
*   This method can retun null if observer do not exist
*/

/**
 * Delete an observer
 */
base.consul().deleteObserver("service name");
```

#### Observer
Each observer has two methods:
```js
let observer = base.consul().newObserver("service name");
/**
 * Get list with all node wher run that service
 */
 observer.getServices();
 /**
 * Get the current error if getServices return empty array
 */
 observer.getError();
```