1.1.26 • Published 6 months ago

@m-backend/core v1.1.26

Weekly downloads
-
License
-
Repository
-
Last release
6 months ago

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.

OptionDescription
prefixThe prefix applied to each routes defined by the controller
appThe 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 {
		/* ... */
	}
}
1.1.26

6 months ago

1.1.23

1 year ago

1.1.25

11 months ago

1.1.24

11 months ago

1.1.22

1 year ago

1.1.21

1 year ago

1.1.20

1 year ago

1.1.19

2 years ago

1.1.18

2 years ago

1.1.17

2 years ago

1.1.16

2 years ago

1.1.15

2 years ago

1.1.14

2 years ago

1.1.9

2 years ago

1.1.12

2 years ago

1.1.11

2 years ago

1.1.10

2 years ago

1.1.13

2 years ago

1.1.8

2 years ago

1.1.7

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.1.3

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.0

2 years ago

0.0.1

2 years ago