let api
module.exports = class Action {
/**
* Create a new ActionHero Action. The required properties of an action. These can be defined statically (this.name) or as methods which return a value.
*
* @class ActionHero.Action
*
* @property {string} name - The name of the Action.
* @property {string} description - The description of the Action (default this.name).
* @property {Number} version - The version of this Action (default: 1).
* @property {Object} outputExample - An example response payload (default: {}).
* @property {Object} inputs - The inputs of the Action (default: {}).
* @property {Array} middleware - The Middleware specifit to this Action (default: []). Middleware is descibed by the string names of the middleware.
* @property {Array} blockedConnectionTypes - Are there connections from any servers which cannot use this Action (default: [])?
* @property {string} logLevel - Under what level should connections to this Action be logged (default 'info')?
* @property {Boolean} matchExtensionMimeType - If this Action is responding to a `web` request, and that request has a file extension like *.jpg, should ActionHero set the response headers to match that extension (default: true)?
* @property {Boolean} toDocument - Should this Action appear in api.documenation.documenation? (default: true)?
*
* @tutorial actions
* @example
'use strict'
const ActionHero = require('actionhero')
module.exports = class RandomNumber extends ActionHero.Action {
constructor () {
super()
this.name = 'randomNumber'
this.description = 'I am an API method which will generate a random number'
this.outputExample = {randomNumber: 0.1234}
}
async run (data) {
data.response.randomNumber = Math.random()
}
}
*/
constructor () {
// Only in files required by `index.js` do we need to delay the loading of the API object
// This is due to cyclical require issues
api = require('./../index.js').api
let coreProperties = this.coreProperties()
for (let key in coreProperties) {
if (!this[key]) { this[key] = coreProperties[key] }
if (typeof this[key] === 'function') { this[key] = this[key]() }
}
}
/**
* @function run
* @async
* @memberof ActionHero.Action
* @param {Object} data The data about this connection, response, and params.
* @description The main "do something" method for this action. It can be `async`. Usually the goal of this run method is to set properties on `data.response`. If error is thrown in this method, it will be logged, caught, and appended to `data.response.error`
*/
coreProperties () {
return {
name: null,
version: 1,
description: this.name,
outputExample: {},
inputs: {},
middleware: [],
blockedConnectionTypes: [],
logLevel: 'info',
matchExtensionMimeType: true,
toDocument: true
}
}
validate () {
if (!this.name) { throw new Error('name is required for this action') }
if (!this.description) { throw new Error(`description is required for the action \`${this.name}\``) }
if (!this.run || typeof this.run !== 'function') { throw new Error(`action \`${this.name}\` has no run method`) }
if (api.connections && api.connections.allowedVerbs.indexOf(this.name) >= 0) {
throw new Error(`action \`${this.name}\` is a reserved verb for connections. choose a new name`)
}
}
}