@m-backend/core
TypeScript icon, indicating that this package has built-in type declarations

1.1.26 • Public • Published

This library was generated with Nx.

Boilerplate code for M's NodeJS servers.

Table of Content

Install

  • npm install @m-backend/core

Overview

This project allow developers to:

  • Declare services
  • Declare middlewares
  • Use dependency injection and IoC (available in controllers, services, middlewares, application, console).
  • Declare command line interface (using @Console and @Command decorators)

Dependency Injection

@m-backend/core uses the tsyringe package to allow developers to use DI and IoC in your node project.

Services

You can declare services using the Service decorator:

@Service()
export class MyService {}

And use it in other services or controllers:

@Service()
export class OtherService {
	constructor(private myService: MyService) {}
}

Middleware

You can declare a middleware class and use it in other controllers or routes handlers. A middleware class is a singleton and can use DI.

import { Context, Next } from "koa";
import { Middleware, MiddlewareInterface } from "@m-backend/core";

@Middleware()
export class MyMiddleware implements MiddlewareInterface {
	use(ctx: Context, next: Next): any {
		/* ... */
	}
}

You can declare a middleware as application level using the autoloadIn property:

// Add the middleware to the main application (default application in the project template).
@Middleware({ autoloadIn: 'main' })

Routing

To declare a Koa route, you must create a *.controller.ts file and export an annoted controller class as default:

@Controller()
export default class MyController {

	@Get('/user/:id')
	async getUserById() {/* some code here... */}

}

Controller Options

You can set options to the controller annotation.

Option Description
prefix The prefix applied to each routes defined by the controller
app The application name (default to main)

Example:

@Controller({ prefix: '/my_route' })
/*... */

(e.g: the prefix must start with a "/" if it's provided)

Attach middlewares

You can attach middlewares to a controller or methods with the AttachMiddleware decorator:

@AttachMiddleware([/* a list of middleware */])
@Controller()
export default class MyController {}

Note: Middlewares attached to a controller will be called for each controller routes

@Controller()
export default class MyController {

	@AttachMiddleware([/* a list of middleware */])
	@Get('/my/path')
	myPath(ctx: Context) {}

}

Configurations

The package exposes simple API that help load any config file. Note: please keep in mind that those configuration files should be of format .config.json)

Loading a configuration file

Use the loadConfigFile function from the config.ts file:

import { loadConfigFile } from '@m-backend/core';
loadConfigFile('my_config'); // Note: the expected config file name is "my_config.config.json".

Or use the loadConfigFile method from the ConfigService:

@Service()
export default class MyService {
	constructor(private configService: ConfigService) {
		this.configService.loadConfigFile('my-config');
	}
}

Loading a configuration folder

Use the loadConfigFolder function to load multiple configuration files. By default use the /config folder or it can be custom path by giving path as function parameter

import { loadConfigFolder } from '@m-backend/core';

loadConfigFolder();

// OR

loadConfigFolder('your_path_to_configuration_folder');

File extensions are optional and can be managed by a m-backend.json file as follow :

{
    "whitelist": [".config.json", ".md"],
    "blacklist": ["example.config.json", ".sql"]
}

Note :

The function loadConfigFolder calls loadConfigFile after indexing files, so, some extensions can be mismanaged.

The m-backend.json file mustn't change, it's a dev dependency

Get a configuration

Simply:

import { config } from '@m-backend';

config.my_config

Or using the config service

@Service() // Or any other class that use the IoC (Controller/Middleware/etc...
export class MyService {
	constructor(private configService: ConfigService) {
		this.configService.my_config
	}
}

Listen to config changes

Each config files are watched. The config service allows you to listen to these changes:

@Service() // Or any other class that use the IoC (Controller/Middleware/etc...
export class MyService {
	constructor(private configService: ConfigService) {
		this.configService.change$.on(CONFIG_EVENTS.CHANGE, configName => {
			if (configName === 'my_config') {
				// Do something with the new config.
			}
		});
	}
}

Applications

The template provide a koa app instance by default, but you can define and run multiple app at the same time.

To create a new koa app, first create a new file called my_app.app.ts and export a class:

@Application('my_app', MY_APP_PORT)
export default class MyApp extends AbstractApp {}

Now you can use your new app on a specific controller :

@Controller({ app: 'my_app' })
/*...*/

Cron

You can declare a cron job using the @Cron() decorator.

import { Cron } from "@m-backend/core/";

@Cron({ cronTime: '* * * * * *' })

Log

This template include the winston package for app logging.

A service is provided:

/* ... imports, decorators */
export default class MyClass {
	constructor(private logService: LoggerService) {}

	someMethod() {
		this.logService.logger.info('log with info level');
		this.logService.logger.error('log with error level');
		/* etc... */
	}
}

Configure log output

3 type of output are supported by default:

  • Console for a colorful console output
  • No color console for a non-colorful console output
  • File for file generation containing your app logs.

Note: The loggerService uses your app.config.json file for that.

{
	"logger": {
		"level": "silly",
		"transports": [
			{ "type": "console" },
			{
				"type": "file",
				"options": {
					"filename": "app.log",
					"maxsize": 100000,
					"maxFiles": 10,
					"tailable": true,
					"zippedArchive": true
				}
			}
		]
	}
}

Console

This template include the commander package to manage command line arguments and options.

Commander doc.

How to define a command line

import { Console, Command } from "@m-backend/core";

@Console('my-console')
export default class MyConsole extends ConsoleBase {

  /**
   * Simple command line example.
   **/
  @Command('my-cmd', 'my-cmd description')
  async myCmd(): void {
    // ...
  }

  /**
   * Command line example with options.
   * See the commander documentation for command and option syntaxes.
   **/
  @Command('my-cmd2 <myValue>', 'my-cmd description', [
    { option: '-l, -lorem-ipsum [value]', description: 'Lorem ipsum dolor sit amet', default: 42 }
  ])
  async myCmd2(myValue: string, opts: any): void {
    console.log(myValue);
    console.log(opts.loremIpsum);
    // ...
  }

}

Exemple of use:

node app.js my-console:my-cmd

node app.js my-console:my-cmd2 23 -l

Note: The console name is automatically added as a prefix to the command name to avoid name conflicts and allow a better visualization in the result of the help command.

Example

Controller

import { Context } from 'koa';
import { Joi } from '@koa-better-modules/joi-router';
import LoremMiddleware from '@app/lorem.middleware';
import { AttachMiddleware, Controller, LoggerService, Get, Post } from '@m-backend/core';

@AttachMiddleware([LoremMiddleware])
@Controller({ prefix: '/api' })
export default class LoremController {

	constructor (private log: LoggerService) { } //private config: ConfigService, Inject this after fixing default export

	@AttachMiddleware([LoremMiddleware])
	@Get('/ipsum')
	async getIpsum(ctx: Context) {
		ctx.body = { message: 'test ipsum dolor sit amet' };
	}

	@Post('/lorem/:id', {
		body: {
			name: Joi.string().max(100).required(),
			email: Joi.string().lowercase().email().required()
		},
		type: 'json'
	})
	async postLorem(ctx: Context) {
		ctx.response.body = ctx.request.body;
		(ctx.response.body as any).id = ctx.request.params.id;
	}
}

Cron

import { CronJob } from "cron";
import { Cron, OnTick, LoggerService } from "@m-backend/core";

@Cron({ cronTime: '* * * * * *' })
export default class SampleCron implements OnInit, OnTick, OnComplete {

	/**
	 * The cron job instance.
	 * /!\ Not available in the constructor. Use the OnInit interface if you want to start the cron manually.
	 */
	job: CronJob | undefined;

	onInit(): void {
		/* ... init code here. */
		this.job.start(); // Or use the start property in the decorator options.
		setTimeout(() => {
			// Stop the job and call the onComplete callback.
			this.job?.stop();
		}, 5000)
	}

	onTick(): void {
		/* ... */
	}

	onComplete(): void {
		/* ... */
	}
}

Readme

Keywords

none

Package Sidebar

Install

npm i @m-backend/core

Weekly Downloads

0

Version

1.1.26

License

none

Unpacked Size

78.6 kB

Total Files

68

Last publish

Collaborators

  • metromobilite