leaonline:method-factory

v1.1.0Published 3 years ago

Meteor ValidatedMethod Factory

JavaScript Style Guide Project Status: Active – The project has reached a stable, usable state and is being actively developed. GitHub file size in bytes GitHub

Create validated Meteor methods. Lightweight. Simple.

With this package you can define factory functions to create a variety of Meteor methods. Decouples definition from instantiation (also for the schema) and allows different configurations for different types of methods.

Minified size < 2KB!

Why do I want this?

  • Decouple definition from instantiation
  • Just pass in the schema as plain object, instead of manually instantiating SimpleSchema
  • Create fixed mixins on the abstract factory level, on the factory level, or both (see mixins section)

Installation

Simply add this package to your meteor packages

$ meteor add leaonline:method-factory

Usage

Import the createMethodFactory method and create the factory function from it:

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2
3const createMethod = createMethodFactory() // no params = use defaults
4const fancyMethod = createMethod({ name: 'fancy', validate: () => {}, run: () => 'fancy' }) // minimal required
5fancyMethod.call() // 'fancy'

With schema

We support various ways to validate an input schema. To decouple schema definition from instantiation, we introduced a shemaFactory, which is basically a function that creates your schema for this collection. This also ensures, that methods don't share the same schema instances.

Using SimpleSchema

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import SimpleSchema from 'simpl-schema'
3
4const schemaFactory = definitions => new SimpleSchema(definitions)
5
6const createMethod = createMethodFactory({ schemaFactory })
7const fancyMethod = createMethod({
8  name: 'fancy',
9  schema: { title: String },
10  run: function({ title }) {
11    return `Hello, ${title}`
12  }
13})
14fancyMethod.call({ title: 'Mr.x' }) // Hello, Mr.x

As you can see, there is no need to pass a validate function as it is internally built using the schemaFactory and the given schema.

Overriding validate when using schema

You can also override the internal validate when using schema by passing a validate function. This, however, disables the schema validation and is then your responsibility:

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import SimpleSchema from 'simpl-schema'
3
4const schemaFactory = definitions => new SimpleSchema(definitions)
5
6const createMethod = createMethodFactory({ schemaFactory })
7const customValidationMethod = createMethod({
8  name: 'customValidation',
9  schema: { title: String },
10  validate(document) {
11    if (!['Mrs.y', 'Mr.x'].includes(document.title)) {
12     throw new Error()
13    }
14  },
15  run: function({ title }) {
16    return `Hello, ${title}`
17  }
18})
19customValidationMethod.call({ title: 'Dr.z' }) // err

If none of these cover your use case, you can still use mixins.

Using check

You can also use Meteor's builtin check and Match for schema validation:

1import { check } from 'meteor/check'
2import { createMethodFactory } from 'meteor/leaonline:method-factory'
3
4const schemaFactory = schema => ({
5  validate (args) {
6    check(args, schema)
7  }
8})
9
10const createMethod = createMethodFactory({ schemaFactory })
11const fancyMethod = createMethod({
12  name: 'fancyMethod',
13  schema: { title: String },
14  run: function({ title }) {
15    return `Hello, ${title}`
16  }
17})
18fancyMethod.call({ title: 'Mr.x' }) // Hello, Mr.x

Note, that some definitions for SimpleSchema and check/Match may differ.

With custom ValidatedMethod

You can extend the ValidatedMethod and pass it to the factory as well. Note, that you need to inherit from ValidatedMethod. Fully custom classes are not supported.

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import { ValidatedMethod } from 'meteor/mdg:validated-method'
3import { myDefaultMixin } from '/path/to/myDefaultMixin'
4
5class CustomMethod extends ValidatedMethod {
6  constructor (options) {
7    if (options.mixins && options.mixins.length > 0) {
8      options.mixins = options.mixins.concat([myDefaultMixin])
9    }  else {
10      options.mixins = [myDefaultMixin]
11    }
12    super(options)
13  }
14}
15
16const createMethod = createMethodFactory({ custom: CustomMethod })
17const customMethod = createMethod({ ... })

With mixins

There are three ways to define mixins:

  • on the abstract factory function level, all methods created by the factory will contain these mixins
  • on the factory level, you basically pass mixins the a single method
  • on both levels, where mixins from the abstract factory function are executed first; no overrides

Abstract factory level mixins

If you want a certain mixin to be included for all methods created by the factory just pass them to the createMethodFactory function:

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import { ValidatedMethod } from 'meteor/mdg:validated-method'
3import { myDefaultMixin } from '/path/to/myDefaultMixin'
4
5const createMethod = createMethodFactory({ mixins: [myDefaultMixin] })
6const someMethod = createMethod({ 
7  name: 'methodWithMixin', 
8  validate: () => {}, 
9  run: () => 'result', 
10  foo: 'bar' // assuming your mixin requires foo 
11})

Factory level mixins

You can also define mixins for each method. This is the same as passing mixins to the ValidatedMethod:

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import { ValidatedMethod } from 'meteor/mdg:validated-method'
3import { myDefaultMixin } from '/path/to/myDefaultMixin'
4
5const createMethod = createMethodFactory() // use defaults
6
7const methodWithMixin = createMethod({ 
8  name: 'methodWithMixin',
9  mixins: [myDefaultMixin],
10  validate: () => {}, 
11  run: () => 'result', 
12  foo: 'bar' // assuming your mixin requires foo 
13})
14
15const methodWithoutMixin = createMethod({
16  name: 'methodWithoutMixin',
17  validate: () => {}, 
18  run: () => 'result', 
19})
Use mixins on both levels

Of course you can define mixins on both levels, so that you have a certain set of default mixins and method-specific mixins:

1import { createMethodFactory } from 'meteor/leaonline:method-factory'
2import { ValidatedMethod } from 'meteor/mdg:validated-method'
3import { myDefaultMixin } from '/path/to/myDefaultMixin'
4import { someOtherMixin } from '/path/to/someOtherMixin'
5
6const createMethod = createMethodFactory({ mixins: [myDefaultMixin] })
7
8const methodWithMixin = createMethod({ 
9  name: 'methodWithMixin', 
10  validate: () => {}, 
11  run: () => 'result', 
12  foo: 'bar' // assuming your mixin requires foo 
13})
14
15const methodWithMixins = createMethod({
16  name: 'methodWithMixin', 
17  mixins: [someOtherMixin],
18  validate: () => {}, 
19  run: () => 'result', 
20  foo: 'bar', // assuming your mixin requires foo
21  bar: 'baz', // assuming the other mixin requires bar 
22})

Codestyle

We use standard as code style and for linting.

via npm
$ npm install --global standard snazzy
$ standard | snazzy
via Meteor npm
$ meteor npm install --global standard snazzy
$ standard | snazzy

Test

We use meteortesting:mocha to run our tests on the package.

Watch mode
$ TEST_WATCH=1 TEST_CLIENT=0 meteor test-packages ./ --driver-package meteortesting:mocha
Cli mode

License

MIT, see LICENSE