UNPKG

periodicjs

Version:

Periodic is a rapid enterprise application framework for data driven web and mobile applications.

318 lines (266 loc) 10.6 kB
# What are Periodic Extensions? Extensions have seven major features. Once an extension is initialized, the extension's features are availble in your periodic application. 1. Commands 2. Configurations 3. Controllers 4. Routers 5. Transforms 6. Utilities 7. Views ## 1. Commands - Asynchronous tasks available to Periodic's CLI A command is a function that is mounted to your periodic application during initialization. Commands are available as CLI tasks through periodic's CLI. ```javascript //You can access extensions commands from resources periodic.resources.commands.extensions; // Map of extenion commands //referencing a single command periodic.resources.commands.extensions.get('[name-of-extesion]')['name-of-command']; // this is a function that returns a promise //during the initialization process, when your application is loading extenstions it loads commands from your extensions command direcotry //for example the extension dbseed const dbseedCommands = require('periodicjs.ext.dbseed/commands/index'); //has an import and an export command periodic.resources.commands.extensions.set('periodicjs.ext.dbseed',dbseedCommands); //using a command periodic.resources.commands.extensions.get('periodicjs.ext.dbseed').export('path/to/some/seedfile.json') .then(console.log) .catch(console.error); ``` E.g. calling command from the CLI ``` $ periodicjs extension periodicjs.ext.dbseed export path/to/some/seedfile.json ``` E.g. calling command from the REPL ```javascript $p.resources.commands.extensions.get('periodicjs.ext.dbseed').export('path/to/some/seedfile.json').then(console.log).catch(console.error); ``` ## 1. Configurations - custom settings for extensions including custom databases Extension configurations are required to have two properties `settings` and `databases` Sample `settings.js` ```javascript module.exports = { settings: { }, databases: { }, }; ``` ### Configuring extension settings ```javascript // once initialized, extension settings are assigned to a name spaced property on your applications extensions setting property periodic.settings.extensions['name-of-extension']; ``` Just like your periodic application, extension settings are composed of default settings, environment settings and override settings ``` Default Settings -> Environment Settings -> Override Settings -> Extension Settings ``` The default settings for an extension are defined in the extensions `name-of-extension/config/settings.js` file. Environment settings are stored in the configuration database under the filepath `content/config/extension content/config/extension/[name-of-extension]/[runtime-environemnt].json` Override Settings are stored in your global override settings `content/config/config.json` under the `settings.extensions['name-of-extension']` property ### Configuring custom extension databases In some situations, extensions need their own databases (e.g. for logging, for caching, shopping carts, etc) The databases setting property is identical to the database setting property in your periodic configuration . Custom database models are located in `name-of-extension/config/databases/[name-of-database]/models` directory Sample extension configuration with custom databases ```javascript 'use strict'; module.exports = { settings: { use_logging:true, validate_customers:true, use_transaction_history:true, }, databases: { error_log_db: { db: 'mongoose', options: { url: 'mongodb://localhost:27017/custom_db_logs', mongoose_options: {}, }, controller: { default: { protocol: { adapter: 'http', api: 'rest', }, responder: { adapter: 'json', }, }, }, router: { ignore_models: [], }, }, transactions: { db: 'sequelize', options: { database: 'store_orders_db', username: '', password: '', connection_options: { dialect: 'postgres', port: 5432, host: '127.0.0.1', logging: true, }, }, controller: { default: { protocol: { adapter: 'http', api: 'rest', }, responder: { adapter: 'json', }, }, }, router: { ignore_models: [], }, }, shopping_cart: { db: 'lowkie', options: { dbpath: 'content/config/settings/shopping-cart_db.json', dboptions: { verbose: true, }, }, controller: { default: { protocol: { adapter: 'http', api: 'rest', }, responder: { adapter: 'json', }, }, }, router: { ignore_models: [], }, }, }, }; ``` ## 3. Controllers - milddleware functions During initialization, an extension's controllers are ```javascript //You can access extensions commands from resources periodic.controllers.extension; // Map of extension middleware controllers ``` Controllers are usually added to an express router, but many extensions export controllers that are intended to be used in custom routes (for example the passport extension) ```javascript const requireAuthentication = periodic.controllers.extension.get('periodicjs.ext.passport').authenticationRequired; const myRouter = periodic.express.Router(); myRouter.get('/auth-required',requireAuthentication,(req,res)=>{ res.send('you are logged in!'); }); ``` Controllers are mounted onto the Periodic controllers map ```javascript periodic.controllers.extension.set(`${extension.name}`, require(`${extension.name}/controllers/index`)); ``` ## 4. Routers - Express routers Extension routers are express routers that are mounted from `name-of-extension/routers/index`, routers are mounted during the express intialization of the application and after all extension resources have been loaded. ```javascript //sample name-of-extension/routers/index.js const periodic = require('periodicjs'); const extensionRouter = periodic.express.Router(); extensionRouter.all('/some-endpoint', (req, res) => { res.send('hello world'); }); module.exports = extensionRouter; ``` Routers are mounted onto the Periodic routers map ```javascript periodic.routers.set(`extension_${extension.name}`, { type: 'extension', router: require(`${extension.name}/routers/index`), }) ``` ## 5. Transforms - Asynchronous tasks available to Periodic's CLI Transforms provide a facility to augment the parameters sent to Core Controller and Core Data, before information is queried from the database (Pre Transforms), and a facility to augment the response data before a request responds with information. Extension tranforms are loaded from `name-of-extension/transforms/index` and are injected globally. The way transforms work are by piping the result of the request object into a series of tranform functions. ```javascript const transformedMiddleware = (req,res,next)=>{ Promisie.pipe([transform1,transform2,transform3])(req) .then(transformedReq=>{ originalMiddleware(transformedReq,res,next) } .catch(next); } //promisie pipe = tranform1(req).then(updatedReq1 => transform2(updatedReq1)).then(updatedReq2 => transform3(updatedReq2)); ``` For example, if you have a user route `/users/:id` for a profile page, and if you wanted to sanitize inputs and concatinate output, you could use tranforms. ```javascript //sample name-of-extension/transforms/index.js 'use strict'; const periodic = require('periodicjs'); function userPreTransform1(req) { return new Promise((resolve, reject) => { const updatedReq = Object.assign({},req,{firstname:req.firstname.toUpperCase()}); resolve(updatedReq); }); } function userPreTransform2(req) { return new Promise((resolve, reject) => { const updatedReq = Object.assign({},req,{lastname:req.lastname.toUpperCase()}); resolve(updatedReq); }); } function testPostTransform(req) { return new Promise((resolve, reject) => { req.user.fullname = `${req.user.firstname} ${req.user.lastname}` resolve(req); }); } module.exports = { pre: { GET: { '/user/:id':[userPreTransform1,userPreTransform2] }, PUT: { } }, post: { GET: { '/user/:id':[testPostTransform] }, PUT: { } } } ``` Transforms are mounted onto the Periodic transforms object ```javascript const tranforms = require(`${extension.name}/transforms/index`); const requestMethods = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'POST']; requestMethods.forEach(reqMethod => { if (transforms.pre) { periodic.transforms.pre[reqMethod] = Object.assign({}, periodic.transforms.pre[reqMethod], transforms.pre[reqMethod]); } if (transforms.post) { periodic.transforms.post[reqMethod] = Object.assign({}, periodic.transforms.post[reqMethod], transforms.post[reqMethod]); } }) ``` ## 6. Utilities - Asynchronous tasks available to Periodic's CLI Each Extension has a utility property that provides a facility share properties across extensions. Utilities are loaded from `name-of-extension/utilities/index`and are mounted on `periodic.locals.extensions` during initialization. Utilities are mounted onto the Periodic extension locals map ```javascript periodic.locals.extensions.set(`${extension.name}`, require(`${extension.name}/utilities/index`)); ``` ## 7. Views - Asynchronous tasks available to Periodic's CLI Extensions have the capability to override default views, by using the same view path, and passing the extension name, when CoreController attempts to load the view, it'll first try to load `app_root/node_modules/views/user/profile` and then fallback to `app_root/app/views/user/profile` ```javascript function someMiddleWareFunction(req, res){ const viewtemplate = { viewname:'user/profile', extname:'name-of-ext', }; const viewdata = req.user.profile; periodic.core.controller.renderView(req, res, viewtemplate, viewdata); } ``` NEXT: [ How do Periodic Extensions work? ](https://github.com/repetere/periodicjs/blob/master/doc/extensions/03-how-are-extensions-loaded.md)