@ourparentcenter/moleculer-decorators-extended
TypeScript icon, indicating that this package has built-in type declarations

2.1.0 • Public • Published

Moleculer logo

npm GitHub issues GitHub license Powered by moleculer

Moleculer Decorators

Decorators for moleculer, Tested & accurate as of 0.14

Http methods supported

  • Checkout - Notify
  • Connect - OptionsVerb
  • Copy - Patch
  • Delete - Post
  • Get - Purge
  • Head - Put
  • Lock - Report
  • Merge - Search
  • MKActivity - Subscribe
  • MKCol - Trace
  • Move - Unlock
  • MSearch - Unsubscribe

Available options

constructOverride: false // True by default, This will override any properties defined in @Service if defined in the constructor as well.
skipHandler: true // false by default, this will let a mixin override the handler in an action. (action options)
mergeActions: true // false by default, this will merge actions defined in `@Service` decorator options with class `@Action` decorator. (action options)

These are defined in @Service

mergeActions

The intention of mergeActions is to facilitate the migration of actions in the Service schema to @Action class decorator. The default value is false and when set to true it will merge the @Service actions with those found in class decorated with @Action. Since the merge is done after the decorator is applied to actions tag of the schema, if an action name in @Service options is the same as that found in the class decorated with @Action, then the @Service options action will overwrite that of @Action in the schema.

To swap between the service option actions and class actions, toggle mergeActions to true to see results of service options actions and false to see results of decorator actions. Only actions that do not have the same name as thier class counterparts will be merged and available when the toggle is set to true.

Example usage

const moleculer = require('moleculer');
const { Service, Action, Event, Method, Get, Post, Put, Patch, Delete } = require('@ourparentcenter/moleculer-decorators-extended');
const web = require('moleculer-web');
const broker = new moleculer.ServiceBroker({
  logger: console,
  logLevel: "debug",
});

@Service({
  mixins: [web],
  mergeActions: true,
  settings: {
    port: 3000,
    routes: [
      ...
    ]
  },
  actions: {...}
})
class ServiceName extends moleculer.Service {

  // Optional constructor
  constructor() {
    this.settings = { // Overrides above by default, to prevent this, add "constructOverride: false" to @Service
      port: 3001
    }
  }

  // Without constructor (typescript)
  settings = {
    port: 3001
  }

  @Action()
  Login(ctx) {
    ...
  }

  @Action({
    skipHandler: true // Any options will be merged with the mixin's action.
  })
  Login3() { // this function will never be called since a mixin will override it, unless you specify skipHandler: false.

  }

  // With options
  // No need for "handler:{}" here
  @Action({
    cache: false,
    params: {
      a: "number",
      b: "number"
    }
  })
  Login2(ctx) {
    ...
  }

  // Get, Post, Put, Patch, Delete follow the same syntax below
  @Get('/user', {
    params: {
      id: "string"
    }
  })
  getUser(ctx) {
      ...
  }

  @Event({
    group: 'group_name'
  })
  'event.name'(payload, sender, eventName) {
    ...
  }

  @Event()
  'event.name'(payload, sender, eventName) {
    ...
  }

  @Method
  authorize(ctx, route, req, res) {
    ...
  }

  @ServiceCreated() { // Passes to moleculer created lifecycle, fired when created
    ...
  }

  @ServiceMerged() { // Passes to moleculer merged lifecycle, Fired after the service schemas merged and before the service instance created
    ...
  }

  @ServiceStarted() { // Passes to moleculer started lifecycle, fired when started
    ...
  }

  @ServiceStopped() { // Passes to moleculer stopped lifecycle, fired when stopped
    ...
  }
}

broker.createService(ServiceName);
broker.start();

Usage with moleculer-runner

Simply export the service instead of starting a broker manually.

It must be a commonjs module.

  module.exports = ServiceName 

Usage with custom ServiceFactory class

Moleculer allows you to define your own ServiceFactory class, from which your services should inherit.

All you have to do, is pass your custom ServiceFactory to broker options and also extend your services from this class

const moleculer = require('moleculer');
const { Service, Action } = require('@ourparentcenter/moleculer-decorators-extended');

// create new service factory, inheriting from moleculer native Service
class CustomService extends moleculer.Service {
    constructor(broker, schema) {
        super(broker, schema)
    }

    foo() {
        return 'bar';
    }
}

// pass your custom service factory to broker options
const broker = new moleculer.ServiceBroker({
  ServiceFactory: CustomService
});

@Service()
class ServiceName extends CustomService { // extend your service from your custom service factory
  @Action()
  Bar(ctx) {
    return this.foo();
  }
}

broker.createService(CustomService);
broker.start();

Service

The Service class must be used as the base of any decorated service. Most options can be added either by defining them in the class itself or by adding them to the decorator options.

@Service()
class Example extends Service {
    version = 1;
    settings = {};
    metadata = {
        test: "This is a test"
    };
    mixins = [];
}
class Base extends Service {}

@Service({
    name: "Tester",
    version: 1,
    settings: {},
    metadata: {
        test: "This is a test"
    },
    mixins: []
})
class Example2 extends Base {
}

Parameters

Param decorators for Fastest Validator are provided and creating custom param decorators is easy.

This example assumes using the Joi Validator example

import * as Joi from "joi";
import { Service } from "moleculer";

import {
    action,
    param,
    service
} from "moleculer-service-decorators";

function joiString() {
    return param(Joi.string().max(255).required());
}

@Service()
class Example extends Service {
    @Action()
    public help(@joiString() text: string) {}
}

Actions

Actions can have options set in the same format as the ServiceSchema. The handler can be defined with the parameters of the context or you can set the parameters in the action options and use a Context as the only parameter to the handler.

import { Service } from "moleculer";

@Service()
class Example extends Service {
    @Action({
        name: "getHelp",
        cache: true,
        metrics: { params: false, meta: true }
    })
    public help(@string() text: string) {}
}

@Service()
class Example2 extends Service {
    @Action({
        name: "getHelp",
        cache: true,
        metrics: { params: false, meta: true },
        params: {
            text: "string"
        }
    })
    public help(ctx: Context) {}
}

Events

Event handlers are added easily with options available to make it more flexible.

import { Service } from "moleculer";

@Service()
class Example extends Service {
    @Event()
    public "test.started"(payload: any, sender: string, eventName: string) {}

    @Event({ name: "test.ended", group: "test" })
    public testEnded(payload: any, sender: string, eventName: string) {}
}

Rest

Rest actions make adding api endpoints easy. The current rest methods are GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD, CONNECT, TRACE.

import { Service } from "moleculer";

@Service()
class Example extends Service {
    @Get('/logout', {
		name: 'logout',
		restricted: ['api'],
	})
	logout(ctx: Context<Record<string, unknown>, UserAuthMeta>) {
		...
	}

    @Post('/', {
		name: 'create',
		roles: UserRole.SUPERADMIN,
		restricted: ['api'],
		params: {
			...validateUserBase,
			password: 'string',
			requireRegToken: { type: 'boolean', optional: true },
		},
	})
	async createUser(ctx: Context<UserCreateParams, UserAuthMeta>) {
		...
	}

    @Put('/:id', {
		name: 'modify',
		restricted: ['api', 'user'],
		roles: UserRole.SUPERADMIN,
		params: {
			...validateUserBaseOptional,
			password: { type: 'string', optional: true },
			id: 'string',
		},
	})
	async modifyUser(ctx: Context<UserUpdateParams, UserAuthMeta>) {
		...
	}

    @Patch('/:id', {
		name: 'update',
		restricted: ['api', 'user'],
		roles: UserRole.SUPERADMIN,
		params: {
			...validateUserBaseOptional,
			password: { type: 'string', optional: true },
			id: 'string',
		},
	})
	async updateUser(ctx: Context<UserUpdateParams, UserAuthMeta>) {
		...
	}

    @Delete('/:id', {
		name: 'remove',
		restricted: ['api'],
		roles: UserRole.SUPERADMIN,
		params: { id: 'string' },
	})
	async deleteUser(ctx: Context<UserDeleteParams, UserAuthMeta>) {
		...
	}
}

Lifecycle events

Event handlers are added easily with options available to make it more flexible.

import { Service } from "moleculer";

@Service()
class Example extends Service {
    @ServiceCreated()
    public createdMethod() {
        this.logger.info('Service created')
    }

    @ServiceMerged()
    public mergedMethod() {
        this.logger.info('Service schema merged')
    }

    @ServiceStarted()
    public startedMethod() {
        this.logger.info('Service started')
    }

    @ServiceStopped()
    public stoppedMethod() {
        this.logger.info('Service stopped')
    }
}

License

Moleculer Decorators is available under the MIT license.

Dependents (2)

Package Sidebar

Install

npm i @ourparentcenter/moleculer-decorators-extended

Weekly Downloads

88

Version

2.1.0

License

MIT

Unpacked Size

157 kB

Total Files

6

Last publish

Collaborators

  • karnith