UNPKG

10.8 kBMarkdownView Raw
1## node-mu
2
3A node.js minimalistic microservice framework. At this stage node-mu it is not yet production-ready. It is under heavy testing.
4
5### Release notes
6As of this 0.1.1 version, we introduce Inversion of Control using the [inversify](https://github.com/inversify) IoC container library.
7
8We introduce the new _Producer_ and _Service_ concept.
9All of the _node-mu_ components are now _injectable_ thanks to the relative decorator functions:
10
11* _injectable_
12* _componente_
13* _provider_
14* _route_
15* _controller_
16* _service_
17* _repository_
18* _factoryFunction_
19* _application_
20* _inject_
21
22### Installation
23Using npm:
24````
25$ npm install --save node-mu
26````
27using Yarn:
28````
29$ yarn add node-mu
30````
31
32### Example
33
34config/default.yml
35````
36########################################################################
37# Service configuration.
38#
39# This configuration will be overridden by the NODE_ENV profile you use,
40# for example development.yml for development profile or production.yml
41# for production a so on.
42#
43########################################################################
44
45service:
46 group: Examples
47 name: SimplerService
48 version:
49 major: 0
50 minor: 0
51 status: 0 # 0: alpha, 1: beta, 2: release, 3: final
52
53api:
54 endpoint:
55 port: 5001
56 baseRoutingPath: /api/v2
57 security:
58 enabled: true
59 jwt:
60 secret: configure-here-jwt-secret-for-the-service
61 expiration:
62 enabled: true
63 minutes: 13149000
64
65management:
66 endpoint:
67 port: 5101
68 baseRoutingPath: /mgmt
69 health:
70 path: /health
71 full: true
72
73
74jwt:
75 secret: configure-here-jwt-secret-for-the-service
76 expiration:
77 enabled: true
78 minutes: 13149000
79
80# optional configuration to open a db connection
81db:
82 client: mysql2
83 connection:
84 host: set-here-the-host-of-your-db
85 database: set-here-the-name-of-your-db-schema
86 user: set-here-the-user-name
87 password: set-here-the-user-password
88 charset: utf8
89
90# optional configurtion to open and AMQP connection
91amqp:
92 url: amqp://set-here-a-user:set-here-a-pwd@set-here-the-host:5672/set-here-a-VHOST
93 exchange:
94 name: set_here_the_name_of_an_exchange
95
96events:
97 mapFile: set/here/your/json/file
98
99log:
100 path: ../path/for/log/file
101 console: true|false
102 level: set-here-your-log-level_(INFO,DEBUG,...)
103 json: true|false
104 requests:
105 console: true|false
106 errors:
107 console: true|false
108
109
110# should match your Git repo version
111info:
112 version: your.service.version
113````
114
115events-map.json
116````
117{
118 "events": [
119 {
120 "name": "new_user",
121 "amqpConfig": {
122 "exchange": {
123 "name": "uaa_events",
124 "route": "uaa_new_user_route"
125 }
126 }
127 },
128 {
129 "name": "user_updated",
130 "amqpConfig": {
131 "exchange": {
132 "name": "uaa_events",
133 "route": "uaa_new_user_route"
134 }
135 }
136 },
137 {
138 "name": "user_removed",
139 "amqpConfig": {
140 "exchange": {
141 "name": "uaa_events",
142 "route": "uaa_new_user_route"
143 }
144 }
145 }
146 ]
147}
148````
149
150index.js
151```javascript
152const build = require('../../lib');
153const SimpleService = require('./simple-service');
154
155const start = async () => {;
156 try {
157 const service = build(SimpleService);
158 await service.run();
159 } catch (err) {
160 throw err;
161 }
162};
163
164start()
165 .then(() => {
166 console.log(`\uD83D\uDE80 node-\u03BC service started [pid: ${process.pid}]... bring me some \uD83C\uDF7A \uD83C\uDF7A \uD83C\uDF7A`);
167 }).catch((err) => {
168 console.error(`\uD83D\uDD25 service crashed at startup: ${err}`);
169 process.exit(1);
170});
171```
172
173simple-service.js
174```javascript
175const {container, injectable, component, application, inject} = require('../../lib').ioc;
176const {DbConnectionManager, Api, AmqpConnectionManager, EventsEmitter} = require('../../lib').Providers;
177const Application = require('../../lib').Application;
178const SimpleRoute = require('./simple-route');
179
180module.exports =
181 inject([
182 DbConnectionManager,
183 AmqpConnectionManager,
184 EventsEmitter,
185 Api
186 ],
187 application(
188 class SimpleService extends Application {
189 constructor(dbConnectionManager, amqpConnectionManager, eventsEmitter, api) {
190 super();
191 this.dbConnectionManager = dbConnectionManager;
192 this.amqpConnectionManager = amqpConnectionManager;
193 this.eventsEmitter = eventsEmitter;
194 this.api = api;
195 this._logger.info('SimpleServie started');
196 }
197
198 $bootstrap() {
199 // DO HERE WHAT YOU NEED DURING SERVICE INITIALIZATION
200 }
201 }
202 )
203 );
204```
205
206simple-route.js
207```javascript
208'use strict';
209
210const { inject, route } = require('../../lib').ioc;
211const { Route } = require('../../lib');
212const SimpleController = require('./simple-controller');
213const Joi = require('joi');
214
215const path = '/simple';
216
217module.exports =
218 inject(
219 [SimpleController],
220 route(
221 class SimpleRoute extends Route {
222 constructor(simpleController) {
223 super(path);
224 this._simpleController = simpleController;
225
226 this._setRoutes();
227 }
228
229 _setRoutes() {
230 this.route('/simple').get('/info', this._simpleController.info);
231
232 this.route('/complex', {
233 '/first': {
234 method: ['POST'],
235 headers: {
236 'host': Joi.string().required(),
237 'user-agent': Joi.string().required()
238 },
239 body: {
240 username: Joi.string().required()
241 }
242 }
243 }
244 ).post('/first', (req, res) => {
245 this._logger.debug('****** VALIDATION OK: ' + req.body.username);
246 res.send(req.body.username);
247 }).get('/first', (req, res) => {
248 res.send('/first endpoint OK');
249 });
250 }
251 }
252 )
253 );
254```
255
256simple-controller.js
257```javascript
258'use strict';
259
260const {inject, controller} = require('../../lib').ioc;
261const {ApiEventsEmitterController} = require('../../lib').Controllers;
262const SimpleBusinessService = require('./services/simple-business-service');
263
264module.exports =
265 inject(
266 [SimpleBusinessService],
267 controller(
268 class SimpleController extends ApiEventsEmitterController {
269 constructor(simpleBusinessService) {
270 super();
271 this._simpleBusinessService = simpleBusinessService;
272 }
273
274 async info(req, res, next) {
275 this._logger.info('Request to get info');
276 try {
277 const info = await this._simpleBusinessService.info();
278 res.json(info);
279 } catch (err) {
280 this._logger.error(err);
281 next(err);
282 }
283 }
284 }
285 )
286 );
287```
288
289services/simple-business-service.js
290```javascript
291'use strict'
292
293const { inject, service } = require('../../../lib').ioc;
294const { Service } = require('../../../lib');
295const SimpleRepository = require('../simple-repository');
296
297module.exports =
298 inject(
299 [SimpleRepository],
300 service(
301 class SimpleBusinessService extends Service {
302 constructor(simpleRepository) {
303 super();
304 this._simpleRepository = simpleRepository;
305 }
306
307 async info() {
308 return new Promise(async (resolve, reject) => {
309 try {
310 const user = await this._simpleRepository.findOne({login: 'jstest2111111111111'}, ['authorities']);
311 console.log('\n\nUSER: ' + JSON.stringify(user, null, 2) + '\n\n');
312 resolve(user);
313 } catch (err) {
314 reject(err);
315 }
316 });
317 }
318 }
319 )
320 );
321```
322
323user-model.js
324```javascript
325'use strict';
326
327const Model = require('objection').Model;
328const Authority = require('./authority-model');
329
330
331class User extends Model {
332
333 static get tableName() {
334 return 'USERS';
335 }
336
337 static get jsonSchema() {
338 return {
339 type: 'object',
340 required: ['login', 'activated', 'created_by', 'created_date'],
341 properties: {
342 id: { type: 'bigInteger' },
343 login: { type: 'string', minLength: 1, maxLength:50 },
344 password_hash: { type: 'string', minLength: 1, maxLength: 60 },
345 first_name: { type: 'string', minLength: 1, maxLength: 50 },
346 last_name: { type: 'string', minLength: 1, maxLength: 50 },
347 email: { type: 'string', minLength: 7, maxLength: 100 },
348 image_url: { type: 'string', minLength: 1, maxLength: 256 },
349 activated: { type: 'bit'},
350 lang_key: { type: 'string', minLength: 2, maxLength: 6 },
351 activation_key: { type: 'string', minLength: 1, maxLength: 20 },
352 reset_key: { type: 'string', minLength: 1, maxLength: 20 },
353 created_by: { type: 'string', minLength: 1, maxLength: 50 },
354 created_date: { type: 'timestamp' },
355 reset_date: { type: 'timestamp' },
356 last_modified_by: { type: 'string', minLength: 1, maxLength: 50 },
357 last_modified_date: { type: 'timestamp' }
358 }
359 };
360 }
361
362 static get relationMappings() {
363 return {
364 authorities: {
365 relation: Model.ManyToManyRelation,
366 modelClass: Authority,
367 join: {
368 from: 'user.id',
369 through: {
370 from: 'user_authority.user_id',
371 to: 'user_authority.authority_name'
372 },
373 to: 'authority.name'
374 }
375 }
376 };
377 }
378
379}
380
381module.exports = User;
382```
383
384authority-model.js
385```javascript
386'use strict';
387
388const Model = require('objection').Model;
389
390class Authority extends Model {
391
392 static get tableName() {
393 return 'AUTHORITIES';
394 }
395
396 static get jsonSchema() {
397 return {
398 type: 'object',
399 required: ['name'],
400 properties: {
401 name: { type: 'string', minLength: 1, maxLength: 50 }
402 }
403 };
404 }
405
406 static get relationMappings() {
407 return {
408 users: {
409 relation: Model.ManyToManyRelation,
410 modelClass: __dirname + '/user-model',
411 join: {
412 from: 'authority.name',
413 through: {
414 from: 'user_authority.authority_name',
415 to: 'user_authority.user_id'
416 },
417 to: 'user.id'
418 }
419 }
420 };
421 }
422}
423
424module.exports = Authority;
425```
426
427simple-repository.js
428```javascript
429'use strict';
430
431const {repository} = require('../../lib').ioc;
432const {Repository} = require('../../lib');
433const User = require('./user-model');
434
435module.exports =
436 repository(
437 class SimpleRepository extends Repository {
438 constructor() {
439 super(User);
440 }
441 }
442 );
443```
444
445
446### License
447Licensed under the [MIT license](https://github.com/ITResourcesOSS/node-mu/blob/master/LICENSE).
\No newline at end of file