tensil
TypeScript icon, indicating that this package has built-in type declarations

1.1.31 • Public • Published

Tensil

Express server Service, Controller and Routing framework.

Introduction

Tensil flexible and lightweight. It intentionally leaves out opinion and focuses on painless secure routing. The idea behind Tensil is flexibilty with just enough magic. Services and Controllers can be mounted to the root router or their own router for app segregation.

Install

$ npm install tensil -s

Usage

import tensil, { Controller } from 'tensil';
import * as bodyParser from 'body-parser';
 
class MyController extends Controller {
  // See below for configuring Controllers & Services
  // Excluded here for clarity sake of how to wire up Tensil.
}
 
tensil.app.use(bodyParser.json());
tensil.app.use(bodyParser.urlencoded({ extended: true }));
tensil.app.use(bodyParser.text());
tensil.app.use(bodyParser.json({ type: 'application/json' }));
 
tensil
  .registerController(MyController)
  .start();
 

With Custom App

Using Tensil with external express() app.

import tensil from 'tensil';
import * as express from 'express';
 
const app = express();
tensil.app = app;

With Http Server

Using Tensil with http.createServer

import tensil from 'tensil';
import * as express from 'express';
 
tensil.withServer();
 
// OR
tensil.withServer(express());
 
// OR
tensil.withServer({ options });
 
// OR with SSL
tensil.withServer({ options }, true); // 

Server

Configuring a Tensil Service.

import tensil, { filter, Service } from 'tensil';
import { format } from 'util';
 
class MyService extends Service {
 
  filters: {
    canCreate: ['log', 'isAuthorized']
  }
 
  private formatMessage(message, ...args) {
    return format(message, args);
  }
 
  @filter
  log(req, res, next) {
    // Log a message when this filter is hit.
    console.log(this.formatMessage('Request id', 123456));
    next();
  }
 
  @filter
  isAuthorized(req, res, next) {
    if ('authorized')
      return next();
    res.status(403).send();
  }
 
}
 
const myService = new MyService();
// OR
tensil.registerSerivce(MyService);

Controller

Configuring a Tensil Controller.

import tensil, { action, HttpMethod } from 'tensil';
class MyController extends Tensil.Controller {
 
  // When a custom route or generated route
  // calls "MyController.create" as it's action method
  // the MyService filter "canCreate" is injected.
 
  // The result would be as if you did the following manually:
  // app.post('/user/:id?, ['Myservice.log', 'Myservice.isAuthorized', 'MyController.create'])
 
  policies: {
    create: ['MyService.filters.canCreate'] // 
  }
  
  // or use HttpMethod.Get 
  // or template defined in options like "find"
  // or define with path @action('get', '/some/path/:id?')
  @action() 
  find(req, res) {
    // find a record.
    res.json({});
  }
 
  @action(HttpMethod.Post) 
  create(req, res) {
    // create a record
    res.status(201).json({})
  }
 
}
 
const myController = new MyController('user');
// OR
tensil.registerController(MyController, 'user');

Default Action Templates

Templates allow you to map your action decorators to a key to make the defining of generated routes for controller actions less verbose. You can always override and defined a specific path.

Simply define a template below then use as:

@action('my-template-name')
create(req, res) {
  //
}
const options = {
  templates: {
   get: 'get /{{action}}',
   put: 'put /{{action}}/:id?',
   post: 'post /{{action}}',
   del: 'delete /{{action}}/:id?',
   find: 'get /{{action}}/:id?',
   create: 'post /{{action}}',
   update: 'put /{{action}}/:id?',
   delete: 'delete /{{action}}/:id?',
  }
  formattter: (key, path, type) => {
    // override default formatter function
    // to handle formatting of above templates
    // by default rest routes remove {{action}}
  }
  resttrue,
  crud: false
 
}

Events

A pipe "|" indicates or. By default all errors are emitted without halting by throwing an error. When options.strict is enabled then errors will be thrown. Note when NOT prodcution strict is automatically enabled when strict is undefined. This is done to ensure there are not duplicate registrations and routes in a production environment.

Listening to all events for a given group.

tensil.on(`route`, (type, ...args) => {
  // do something with route.
});

To listen to a specific event type you combine the event with the type separated by a colon. When listening to a specific event type the type is removed from the first argument.

tensil.on(`route:mounted`, (...args) => {
  // do something with route.
});

You can also listen to ALL events as follows:

tensil.on(`*`, (event, type, ...args) => {
  // do something with event.
});
x
Tensil Events
EventTypeValue1Value2
entityduplicateError
policyinvalidError
filterinvalidError
routeduplicateError
routeinvalidError
entityregisteredService | Controller
policycreateIPolicy | IPolicies
filtercreateIFilter | IFilters }
routecreateIRoute | IRoutes
routeregisteredpath: stringIRouteConfig''
routemountedpath: stringIRouteConfig''
mountcompletednull
initcompletednull
startcompletednull

Docs

See https://blujedis.github.io/tensil/

Change

See CHANGE.md

License

See LICENSE.md

Readme

Keywords

none

Package Sidebar

Install

npm i tensil

Weekly Downloads

0

Version

1.1.31

License

ISC

Unpacked Size

1.98 MB

Total Files

101

Last publish

Collaborators

  • blujedis