0.3.7 • Published 6 years ago

node-mu v0.3.7

Weekly downloads
4
License
MIT
Repository
github
Last release
6 years ago

node-mu

A node.js minimalistic microservice framework. At this stage node-mu it is not yet production-ready. It is under heavy testing.

Release notes

v. 0.3.7: now use Reflet metadatas in ioc decorators. v. 0.3.6: fixed a bug in request params validation. v. 0.3.5: fixed timezone in logging timestamp and in health service information. v. 0.3.3: we're back on GitHub! v. 0.1.1: we introduce Inversion of Control using the inversify IoC container library.

We introduce the new Producer and Service concept. All of the node-mu components are now injectable thanks to the relative decorator functions:

  • injectable
  • component
  • provider
  • route
  • controller
  • service
  • repository
  • factoryFunction
  • application
  • inject

Installation

Using npm:

$ npm install --save node-mu

using Yarn:

$ yarn add node-mu

Example

config/default.yml

########################################################################
# Service configuration.
#
# This configuration will be overridden by the NODE_ENV profile you use,
# for example development.yml for development profile or production.yml
# for production a so on.
#
########################################################################

service:
  group: Examples
  name: SimplerService
  version:
    major: 0
    minor: 0
    status: 0   # 0: alpha, 1: beta, 2: release, 3: final

api:
  endpoint:
    port: 5001
    baseRoutingPath: /api/v2
  security:
    enabled: true
    jwt:
      secret: configure-here-jwt-secret-for-the-service
      expiration:
        enabled: true
        minutes: 13149000

management:
  endpoint:
    port: 5101
    baseRoutingPath: /mgmt
  health:
    path: /health
    full: true


jwt:
  secret: configure-here-jwt-secret-for-the-service
  expiration:
    enabled: true
    minutes: 13149000

# optional configuration to open a db connection
db:
  client: mysql2
  connection:
    host: set-here-the-host-of-your-db
    database: set-here-the-name-of-your-db-schema
    user: set-here-the-user-name
    password: set-here-the-user-password
    charset: utf8

# optional configurtion to open and AMQP connection
amqp:
  url: amqp://set-here-a-user:set-here-a-pwd@set-here-the-host:5672/set-here-a-VHOST
  exchange:
    name: set_here_the_name_of_an_exchange

events:
  mapFile: set/here/your/json/file

log:
  path: ../path/for/log/file
  console: true|false
  level: set-here-your-log-level_(INFO,DEBUG,...)
  json: true|false
  requests:
    console: true|false
  errors:
    console: true|false


# should match your Git repo version
info:
  version: your.service.version

events-map.json

{
    "events": [
        {
            "name": "new_user",
            "amqpConfig": {
                "exchange": {
                    "name": "uaa_events",
                    "route": "uaa_new_user_route"
                }
            }
        },
        {
            "name": "user_updated",
            "amqpConfig": {
                "exchange": {
                    "name": "uaa_events",
                    "route": "uaa_new_user_route"
                }
            }
        },
        {
            "name": "user_removed",
            "amqpConfig": {
                "exchange": {
                    "name": "uaa_events",
                    "route": "uaa_new_user_route"
                }
            }
        }
    ]
}

index.js

const build = require('../../lib');
const SimpleService = require('./simple-service');

const start = async () => {;
  try {
    const service = build(SimpleService);
    await service.run();
  } catch (err) {
    throw err;
  }
};

start()
  .then(() => {
    console.log(`\uD83D\uDE80  node-\u03BC service started [pid: ${process.pid}]... bring me some \uD83C\uDF7A \uD83C\uDF7A \uD83C\uDF7A`);
  }).catch((err) => {
  console.error(`\uD83D\uDD25  service crashed at startup: ${err}`);
  process.exit(1);
});

simple-service.js

const {container, injectable, component, application, inject} = require('../../lib').ioc;
const {DbConnectionManager, Api, AmqpConnectionManager, EventsEmitter} = require('../../lib').Providers;
const Application = require('../../lib').Application;
const SimpleRoute = require('./simple-route');

module.exports =
  inject([
      DbConnectionManager,
      AmqpConnectionManager,
      EventsEmitter,
      Api
    ],
    application(
      class SimpleService extends Application {
        constructor(dbConnectionManager, amqpConnectionManager, eventsEmitter, api) {
          super();
          this.dbConnectionManager = dbConnectionManager;
          this.amqpConnectionManager = amqpConnectionManager;
          this.eventsEmitter = eventsEmitter;
          this.api = api;
          this._logger.info('SimpleServie started');
        }

        $bootstrap() {
          // DO HERE WHAT YOU NEED DURING SERVICE INITIALIZATION
        }
      }
    )
  );

simple-route.js

'use strict';

const { inject, route } = require('../../lib').ioc;
const { Route } = require('../../lib');
const SimpleController = require('./simple-controller');
const Joi = require('joi');

const path = '/simple';

module.exports =
  inject(
    [SimpleController],
    route(
      class SimpleRoute extends Route {
        constructor(simpleController) {
          super(path);
          this._simpleController = simpleController;

          this._setRoutes();
        }

        _setRoutes() {
          this.route('/simple').get('/info', this._simpleController.info);

          this.route('/complex', {
              '/first': {
                method: ['POST'],
                headers: {
                  'host': Joi.string().required(),
                  'user-agent': Joi.string().required()
                },
                body: {
                  username: Joi.string().required()
                }
              }
            }
          ).post('/first', (req, res) => {
            this._logger.debug('****** VALIDATION OK: ' + req.body.username);
            res.send(req.body.username);
          }).get('/first', (req, res) => {
            res.send('/first endpoint OK');
          });
        }
      }
    )
  );

simple-controller.js

'use strict';

const {inject, controller} = require('../../lib').ioc;
const {ApiEventsEmitterController} = require('../../lib').Controllers;
const SimpleBusinessService = require('./services/simple-business-service');

module.exports =
  inject(
    [SimpleBusinessService],
    controller(
      class SimpleController extends ApiEventsEmitterController {
        constructor(simpleBusinessService) {
          super();
          this._simpleBusinessService = simpleBusinessService;
        }

        async info(req, res, next) {
          this._logger.info('Request to get info');
          try {
            const info = await this._simpleBusinessService.info();
            res.json(info);
          } catch (err) {
            this._logger.error(err);
            next(err);
          }
        }
      }
    )
  );

services/simple-business-service.js

'use strict'

const { inject, service } = require('../../../lib').ioc;
const { Service } = require('../../../lib');
const SimpleRepository = require('../simple-repository');

module.exports =
  inject(
    [SimpleRepository],
    service(
      class SimpleBusinessService extends Service  {
        constructor(simpleRepository) {
          super();
          this._simpleRepository = simpleRepository;
        }

        async info() {
          return new Promise(async (resolve, reject) => {
            try {
              const user = await this._simpleRepository.findOne({login: 'jstest2111111111111'}, ['authorities']);
              console.log('\n\nUSER: ' + JSON.stringify(user, null, 2) + '\n\n');
              resolve(user);
            } catch (err) {
              reject(err);
            }
          });
        }
      }
    )
  );

user-model.js

'use strict';

const Model = require('objection').Model;
const Authority = require('./authority-model');


class User extends Model {

  static get tableName() {
    return 'USERS';
  }

  static get jsonSchema() {
    return {
      type: 'object',
      required: ['login', 'activated', 'created_by', 'created_date'],
      properties: {
        id: { type: 'bigInteger' },
        login: { type: 'string', minLength: 1, maxLength:50 },
        password_hash: { type: 'string', minLength: 1, maxLength: 60 },
        first_name: { type: 'string', minLength: 1, maxLength: 50 },
        last_name: { type: 'string', minLength: 1, maxLength: 50 },
        email: { type: 'string', minLength: 7, maxLength: 100 },
        image_url: { type: 'string', minLength: 1, maxLength: 256 },
        activated: { type: 'bit'},
        lang_key: { type: 'string', minLength: 2, maxLength: 6 },
        activation_key: { type: 'string', minLength: 1, maxLength: 20 },
        reset_key: { type: 'string', minLength: 1, maxLength: 20 },
        created_by: { type: 'string', minLength: 1, maxLength: 50 },
        created_date: { type: 'timestamp' },
        reset_date: { type: 'timestamp' },
        last_modified_by: { type: 'string', minLength: 1, maxLength: 50 },
        last_modified_date: { type: 'timestamp' }
      }
    };
  }

  static get relationMappings() {
    return {
      authorities: {
        relation: Model.ManyToManyRelation,
        modelClass: Authority,
        join: {
          from: 'user.id',
          through: {
            from: 'user_authority.user_id',
            to: 'user_authority.authority_name'
          },
          to: 'authority.name'
        }
      }
    };
  }

}

module.exports = User;

authority-model.js

'use strict';

const Model = require('objection').Model;

class Authority extends Model {

  static get tableName() {
    return 'AUTHORITIES';
  }

  static get jsonSchema() {
    return {
      type: 'object',
      required: ['name'],
      properties: {
        name: { type: 'string', minLength: 1, maxLength: 50 }
      }
    };
  }

  static get relationMappings() {
    return {
      users: {
        relation: Model.ManyToManyRelation,
        modelClass: __dirname + '/user-model',
        join: {
          from: 'authority.name',
          through: {
            from: 'user_authority.authority_name',
            to: 'user_authority.user_id'
          },
          to: 'user.id'
        }
      }
    };
  }
}

module.exports = Authority;

simple-repository.js

'use strict';

const {repository} = require('../../lib').ioc;
const {Repository} = require('../../lib');
const User = require('./user-model');

module.exports =
  repository(
    class SimpleRepository extends Repository {
      constructor() {
        super(User);
      }
    }
  );

License

Licensed under the MIT license.

0.3.7

6 years ago

0.3.6

6 years ago

0.3.5

6 years ago

0.3.4

6 years ago

0.3.3

6 years ago

0.3.2

6 years ago

0.3.1

6 years ago

0.3.0

6 years ago

0.2.9

6 years ago

0.2.8

6 years ago

0.2.7

6 years ago

0.2.6

6 years ago

0.2.5

6 years ago

0.2.4

6 years ago

0.2.3

6 years ago

0.2.2

6 years ago

0.2.1

6 years ago

0.2.0

6 years ago

0.1.9

6 years ago

0.1.8

6 years ago

0.1.7

6 years ago

0.1.6

6 years ago

0.1.5

6 years ago

0.1.4

6 years ago

0.1.3

6 years ago

0.1.2

6 years ago

0.1.1

6 years ago

0.0.7

6 years ago

0.0.6

6 years ago

0.0.5

6 years ago

0.0.4

6 years ago

0.0.3

6 years ago

0.0.2

6 years ago

0.0.1

6 years ago