@comodinx/microservice

0.1.2 • Public • Published

@comodinx/microservice

Node.js microservice base helpers.

Index

Download & Install

NPM

npm i @comodinx/microservice

Source code

git clone https://gitlab.com/comodinx/microservice.git
cd microservice
npm i

How is it used?

NOTE: Based on bluebird promises.

Getting started

const pkg = require('./package.json');
const { app, listen } = require('@comodinx/microservice/server');
const { errors, health } = require('@comodinx/microservice/server/routes');

app.get('/', (req, res) => res.send('Hello World!'));

// Handle route for health check
health(app, { pkg /* , router, database, services: ['other-service-name'] */ });

// Handle all errors (400, 404, 500, etc...)
errors(app);

listen(app);
/*
 * Listen routes
 *  + GET  /        Home
 *  + GET  /health  Health check
 *  + ANY  /*       404 error. {code: 404, error: 'Not Found'}
 */

Configure

For app/server.

Environment variable Values Type Default value Description
SERVER_HOST host name string undefined Host name where the server listens
SERVER_PORT / PORT port number number 8000 Port where the server listens
SERVER_MULTIPART true/false boolean false Indicate if app use support for multipart middleware
SERVER_HEALTH_PATH health check path string "/health" Route for health check endpoint
BODY_PARSER_LIMIT request limit string "5mb" Indicate request size limit (generic, apply to raw, text, json and urlencoded)
BODY_PARSER_RAW_LIMIT request limit for raw string "5mb" Indicate request size limit for raw
BODY_PARSER_TEXT_LIMIT request limit for text string "5mb" Indicate request size limit for text
BODY_PARSER_JSON_LIMIT request limit for json string "5mb" Indicate request size limit for json
BODY_PARSER_URLENCODED_LIMIT request limit for url encoded string "5mb" Indicate request size limit for url encoded

(go to top)

For database

Simple configuration
Environment variable Values Type Default value Description
DB_ENABLED true/false boolean true Indicate if need support for database
DB_NAME database name string null
DB_HOST database host name string 'localhost'
DB_PORT database port number 3306
DB_USER database user string 'username'
DB_PASS database password string null
DB_TIMEZONE database timezone string '+00:00'

(go to top)

Read/Write replication configuration
Environment variable Values Type Default value Description
DB_HOST_WRITE database host name string DB_HOST Database host name for write replication
DB_PORT_WRITE database port number DB_PORT Database port for write replication
DB_USER_WRITE database user string DB_USER Database username for write replication
DB_PASS_WRITE database password string DB_PORT Database password for write replication
DB_HOST_READ database host name string DB_HOST Database host name for read replication
DB_PORT_READ database port number DB_PORT Database port for read replication
DB_USER_READ database user string DB_USER Database username for read replication
DB_PASS_READ database password string DB_PORT Database password for read replication

(go to top)

Pool configuration
Environment variable Values Type Default value Description
DB_POOL_ENABLED true/false boolean true Indicate if need support for db pool connections
DB_POOL_MAX max pool connections number 10 Maximum number of connection in pool
DB_POOL_MIN min pool connections number 0 Minimum number of connection in pool
DB_POOL_IDLE max idle time number 10000 Maximum time, in milliseconds, that a connection can be idle before being released
DB_POOL_ACQUIRE max time reconnect number 60000 Maximum time, in milliseconds, that pool will try to get connection before throwing error
DB_POOL_EVICT interval time number 1000 Time interval, in milliseconds, after which sequelize-pool will remove idle connections

(go to top)

For services

Environment variable Values Type Default value Description
SERVICE_AGENT service agent name string ''
SERVICE_CONNECTION_TIMEOUT number in miliseconds number 21000
SERVICE_REQUEST_TIMEOUT number in miliseconds number 20000

(go to top)

For global dependencies

Environment variable Values Type Default value Description
DEFAULT_LOCALE locale string 'es' Default locale
MOMENT_LOCALE locale string DEFAULT_LOCALE Default locale for moment module
MOMENT_DEFAULT_FORMAT date format string 'YYYY-MM-DD HH:mm:ss' Default format for moment.format
NUMERAL_LOCALE locale string DEFAULT_LOCALE Default locale for numeral module
NUMERAL_DEFAULT_INTEGER_FORMAT number format string '0,0' Example usage numeral(1000).format(numeral.defaultIntegerFormat)
NUMERAL_DEFAULT_DECIMAL_FORMAT number format string '0,0.00' Example usage numeral(10.01).format(numeral.defaultDecimalFormat)
NUMERAL_DEFAULT_BALANCE_FORMAT number format string '$ 0,0.00' Example usage numeral(100.2).format(numeral.defaultBalanceFormat)
LODASH_TRUNCATE_LENGTH length number 24 Default truncate length use for lodash. Example usage _.truncate('hi-diddly-ho there');
LODASH_TRUNCATE_SEPARATOR string separator string ' ' Default truncate separatotr use for lodash. Example usage _.truncate('hi diddly there');

(go to top)

Detailed explanation

Server

const {
    // Base express application instance
    //  Example usage:
    //   app.get('/', (req, res) => res.send('Hello World!'));
    app,

    // Listen express application instance.
    // If the `config('server.https.enabled')` is false, listen from the express application instance will be executed.
    // If the `config('server.https.enabled')` is true, listen from the instance of https.createServer({ key, cert }) will be executed.
    //  Example usage:
    //   listen(app);
    //
    // NOTE: Listen does nothing when NODE_ENV=test
    listen
} = require('@comodinx/microservice/server');

(go to top)

Routes

const {
    // Routes for error handling. Handle all responses errors (400, 404, 500, etc...)
    errors,

    // Route for health check.
    health
} = require('@comodinx/microservice/server/routes');
Examples for errors

Simple usage

errors(app);
Examples for health

Simple usage

health(app);

Complex usage

health(/* express appplication or express.Router */ app, {

  // To be able to change the url of health check.
  url: '/health',

  // To be able to import package.json and tag.json if they exist. <process.cwd()>
  rootDir: null,

  // For add package information details on health response. (name, description and version) <require('./package.json')>
  pkg: null,

  // For add tag details on health response. <{commit, version, name}>
  tag: null,

  // IDEM url. Default `url`
  path: null,

  // In order to run the health check on a specific router (express.Router).
  router: null,

  // For add database information details on health response. (is alive, error). <database instance require('@comodinx/sequelize')>
  database: null,

  // For add required services information details on health response. (is alive, error) <string list of services added to @comodinx/microservice/helpers/service>
  service: null
});

(go to top)

Get by ID

Get model by id

const Route = require('@comodinx/microservice/server/routes/getById');

const route = new Route('YourModel', {
    // Indicates the name of the parameter to search in `req.params`. Default 'id'
    paramNameId: 'id',

    // Indicates the validation that will be applied to the parameter. Default 'isInteger'
    // Possible values:
    //  Function
    //    Example:
    //      function (id, req) { return id > 10; }
    //  String (https://www.gitlab.com/comodinx/microservice#validator)
    validatorIdType: 'isInteger'
});

module.exports = route.handlerize();

(go to top)

Destroy

Delete model. (**WARNING** - Physical erasure! If req.query.force = true)

const Route = require('@comodinx/microservice/server/routes/destroy');

const route = new Route('YourModel', {
    // Indicates the name of the parameter to search in `req.params`. Default 'id'
    paramNameId: 'id',

    // Indicates the validation that will be applied to the parameter. Default 'isInteger'
    // Possible values:
    //  Function
    //    Example:
    //      function (id, req) { return id > 10; }
    //  String (https://www.gitlab.com/comodinx/microservice#validator)
    validatorIdType: 'isInteger'
});

module.exports = route.handlerize();

(go to top)

List

DEPRECATED List (pagination, filter, order and group) from database model

const Route = require('@comodinx/microservice/server/routes/list');

const route = new Route('YourModel', {
    // Indicates the page size. Default 10
    defaultPageSize: 10,

    // Indicates the validation that will be applied to the parameter. Default null
    // Possible values:
    //  Object with key-value, where the key is the name of the parameter in the filter, and the value is the name of the column in the database
    //    Example:
    //      { idType: 'id_yourmodel_type' }
    mapKeyParse: null
});

module.exports = route.handlerize();

(go to top)

List by query

List (pagination, filter, order and group) from database model

const Route = require('@comodinx/microservice/server/routes/listByQuery');

const route = new Route('User', {
    // Relationship with others tables or services. Default value is null
    relationships: [
        // Example for related table
        {
            // relationship name
            name: 'attributes',
            // related table name
            table: 'job_candidates',
            // field needed from related table for join relationship
            fieldSource: 'candidates.id_job',
            // field needed from model for match join relationship
            fieldTarget: 'jobs.id'
        },

        // Example for related with remote service
        {
            // relationship name
            name: 'person',
            // indicate that relationship is with a remote service
            remote: 'true',
            // service name. helpers/service[<service name>]
            service: 'people',
            // url of remote endpoint
            uri: '/people',
            // field needed from remote service for join relationship
            fieldSource: 'id',
            // field needed from model for match join relationship
            fieldTarget: 'users.id_person'
        }
    ],

    // Indicates the page size. Default 10
    defaultPageSize: 10,

    // Indicates the validation that will be applied to the parameter. Default null
    // Possible values:
    //  Object with key-value, where the key is the name of the parameter in the filter, and the value is the name of the column in the database
    //    Example:
    //      { idType: 'id_yourmodel_type' }
    mapKeyParse: null
});

module.exports = route.handlerize();

(go to top)

Proxy

Handrails between microservices

const Route = require('@comodinx/microservice/server/routes/proxy');

const route = new Route({
    // Indicates the service name defined on @comodinx/microservice/helpers/service.
    serviceName: 'myService',

    // Indicates the function use on service instance. Default `req.method`
    serviceMethod: req.method,

    // Indicates the path use when calling service. Default `req.path`
    serviceUrl: req.path,

    // Extra service request options. Default `{}`
    serviceOptions: {
      responseType: 'json'
    },

    // Indicate if response with the same service response content type.
    sameContentType: true

    // TODO :: Send in service request, the same header from original request
    // headers: [
    //   'authorization'
    // ]
});

module.exports = route.handlerize();
Base route
const _ = require('lodash');
const Base = require('@comodinx/microservice/server/routes');
const { validator } = require('@comodinx/microservice/helpers');
const { errors, database } = require('@comodinx/microservice');
// ...
class Route extends Base {
    /**
     * Validate request
     */
    validate (req) {
        if (_.isEmpty(req.params)) {
            throw new errors.BadRequest('Bad request. Please set "id" parameter');
        }
        if (!validator.isInteger(req.params.id)) {
            throw new errors.BadRequest('Bad request. Please use "id" on parameters');
        }
        return req;
    }

    /**
     * Handle request
     */
    handler (req) {
        return database.models.YourModel.getById(req.params.id).then(model => {
            if (!model) {
                throw new errors.NotFound(`Not found model ${context.id}`);
            }
            return model;
        });
    }
}

module.exports = (new Route()).handlerize();

(go to top)

Config

In order to see all config documentation click here

const { config } = require('@comodinx/microservice');
// ...
// Read configuration
config('server.port'); // 8000

// Extend current configuration.
config.extend({ server: { port: 8001 } });
config('server.port'); // 8001

// Use default value.
config('server.port2', 8001); // 8001

(go to top)

Database

In order to see all database documentation click here

database instance
const { errors, database } = require('@comodinx/microservice');
// ...
return database.models.YourModel.getById(id).then(yourModel => {
    if (!yourModel) {
        throw new errors.NotFound(`Model not found ${id}`);
    }
    return yourModel;
});

Example use raw database, function query

In order to see all operators click here

const { database } = require('@comodinx/microservice');
// ...
return database.models.YourModel.find({
    where: {
        deleted_at: {
            [database.Op.is]: null
        }
    },
    order: [['id', 'DESC']],
    limit: 100,
    offset: 0
});

Example use raw database, function query

In order to see all query types click here

const { database } = require('@comodinx/microservice');
// ...
return database.query('UPDATE users SET active = 0 WHERE id = 1', { type: database.QueryTypes.UPDATE }).spread((results, metadata) => {
    // ...
    return metadata;
});
database model

Bear in mind that everything has an order. Extending the models (for now) requires an order in the require

In the first file of our app / microservice, we have to do the require in the following order

// Setting
require('./config');

// Dependencies
require('@comodinx/microservice/helpers/dependencies');

// Our model extensions
require('./models');

...
Example add extra functionality on model.

File path models/organizations.js

File source:

const { database, database: { Model } } = require('@comodinx/microservice');

class Organizations extends Model {
    /*
     * Function used for populate relationships when model if loaded.
     */
    populate (organization, options) {
        options = options || {};

        if ((options.tiny && !options.with) || options.small) {
            return super.populate(organization, options);
        }

        return super.populate(organization, options)
            // Load users, from remote users service, related with the organization.
            .then(() => this.populateRemotes(organization, 'users', options));
    }

    /*
     * Another extra function
     */
    findAllActives () {
        // ...
    }
}

// Export model Organizations, and extend model organizations on database instance.
module.exports = database.models.Organizations = Organizations;

Usage model extension:

const { database } = require('@comodinx/microservice');

database.models.Organizations.findAllActives().then(models => ...);

(go to top)

Errors

const { errors } = require('@comodinx/microservice');
// ...
throw new errors.NotFound();
// All HTTP Status Code are an Exception
const e = new errors.NotFound('My custom message', {hello: 'world'});
// ...
console.log(e.toJson());
// { "error": 'My custom message', "code": 404, "extra": { "hello": "world" } }

(go to top)

Validator

In order to see all validation functions click here

const validator = require('@comodinx/microservice/helpers/validator');

validator.isEmail('johndoe@gmail.com'); // true
Custom validations.
Integer
validator.isInteger(); // false
validator.isInteger(null); // false
validator.isInteger('a'); // false
validator.isInteger('6'); // true
validator.isInteger('6.1'); // false
validator.isInteger('-6'); // true
validator.isInteger(6); // true
validator.isInteger(6.1); // false
validator.isInteger(-6); // true
Number
validator.isNumber(); // false
validator.isNumber(null); // false
validator.isNumber('a'); // false
validator.isNumber('6'); // true
validator.isNumber('6.1'); // true
validator.isNumber('-6'); // true
validator.isNumber(6); // true
validator.isNumber(6.1); // true
validator.isNumber(-6); // true

(go to top)

Logger

const logger = require('@comodinx/microservice/helpers/logger');

logger.error(new Error('Not Found')); // [2020-01-28T17:16:50.379Z] - ERROR - ✘ Ooops... Error: Not Found
logger.error('This is an error');     // [2020-01-28T17:16:50.379Z] - ERROR - ✘ Ooops... This is an error
logger.warn('This is a warning');     // [2020-01-28T17:16:50.381Z] - WARN - ⚠ This is a warning
logger.info('Hello World!');          // [2020-01-28T17:16:50.381Z] - INFO - Hello World!
logger.title('Hello World!');         // [2020-01-28T17:16:50.382Z] - INFO - ==========   Hello World!   ==========
logger.success('Hello World!');       // [2020-01-28T17:16:50.383Z] - INFO - ✔ Hello World!
logger.arrow('Hello World!');         // [2020-01-28T17:16:50.384Z] - INFO - • Hello World!
logger.step('Hello World!');          // [2020-01-28T17:16:50.384Z] - INFO - ✦ Hello World!
logger.lap('Hello World!');           // [2020-01-28T17:16:50.384Z] - INFO - ➜ Hello World!

(go to top)

Tests

In order to see more concrete examples, I INVITE YOU TO LOOK AT THE TESTS :)

Run the unit tests

npm test

(go to top)

Readme

Keywords

none

Package Sidebar

Install

npm i @comodinx/microservice

Weekly Downloads

0

Version

0.1.2

License

ISC

Unpacked Size

160 kB

Total Files

65

Last publish

Collaborators

  • comodinx