raveljs/ravel

View on GitHub
lib/core/decorators/before.js

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
'use strict';

const $err = require('../../util/application_error');
const Metadata = require('../../util/meta');

/**
 * The `@before` decorator for `Routes` and `Resource` classes. Indicates that
 * certain middleware should be placed on the given route before the method
 * which is decorated.
 *
 * Can also be applied at the class-level to place middleware before *all*
 * `@mapping` handlers.
 *
 * References any middleware `AsyncFunction`s available on `this`.
 *
 * @param {...string} rest - The property names of valid middleware available on `this`.
 * @example
 * // Note: decorator works the same way on Routes or Resource classes
 *
 * const inject = require('ravel').inject;
 * const Routes = require('ravel').Routes;
 * const mapping = Routes.mapping;
 * const before = Routes.before;
 *
 * // @Routes('/')
 * // @inject('koa-bodyparser')
 * class MyRoutes {
 *   constructor (bodyParser) {
 *     this.bodyParser = bodyParser();
 *   }
 *
 *   // @mapping(Routes.GET, '/projects/:id')
 *   // @before('bodyParser') // method-level version only applies to this route
 *   async handler (ctx) {
 *     // in here, bodyParser will already have run,
 *     // and ctx.request.body will be populated
 *   }
 * }
 * @example
 * // Note: decorator works the same way on Routes or Resource classes
 * const inject = require('ravel').inject;
 * const Routes = require('ravel').Resource;
 * const before = Resource.before;
 *
 * // @Resource('/')
 * // @inject('koa-bodyparser')
 * // @before('bodyParser') // class-level version applies to all routes in class.
 * class MyResource {
 *   constructor (bodyParser) {
 *     this.bodyParser = bodyParser();
 *   }
 *
 *   async get(ctx) {
 *     // in here, bodyParser will already have run,
 *     // and ctx.request.body will be populated
 *   }
 * }
 */
function before (...rest) {
  for (const r of rest) {
    if (typeof r !== 'string') {
      throw new $err.IllegalValue('Values supplied to @before decorator must be strings.');
    }
  }

  return function (target, key) {
    // TODO ensure that this is only used on Resources and Routes
    if (rest.length === 0) {
      throw new $err.NotFound(`Empty @before supplied on method ${key} of Resource ${typeof target}`);
    } else if (key === undefined) {
      Metadata.putClassMeta(target.prototype, '@before', 'middleware', rest);
    } else {
      Metadata.putMethodMeta(target, key, '@before', 'middleware', rest);
    }
  };
}

/*!
 * Export the `@before` decorator
 */
module.exports = before;