Package Exports
- hook-middleware-decorators
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (hook-middleware-decorators) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Hook Middleware Decorators
Add and remove pre, post, and "around" middleware hooks to class methods on a per class instance basis with the help of class and method decorators.
How To Use
import { Hooks, Hook, HookAsync, hasHooks } from 'hook-middleware-decorators'
@Hooks()
class ClassWithHooks {
@Hook()
hello(person: string) {
const message = `Hello ${person}`;
console.log(message);
return message;
}
@HookAsync()
async helloAsync(person: string) {
const message = `Hello ${person} async`;
console.log(message);
return message;
}
noHook(person: string) {
const message = `No hook called with ${person}`
console.log(message);
return message;
}
}
function preHello(person: string){
console.log('pre', person)
}
function postHello(message: string, person: string){
console.log('post', message, person)
}
function aroundHello(func: (person: string)=>string, person: string): string {
console.log('before hello', person);
const result = func(person);
console.log('after hello', result);
return result;
}
const instance = new ClassWithHooks();
let helloUnsubscriber = () => {}
if(hasHooks<ClassWithHooks>(instance)) { // type-guard to ensure the class is decorated with @Hooks
helloUnsubscriber = instance.around('hello', aroundHello);
instance.pre('hello', preHello);
instance.post('hello', postHello);
instance.pre('helloAsync', preHello);
instance.post('helloAsync', postHello);
instance.pre('noHook', preHello);
instance.post('noHook', postHello);
}
(async () => {
instance.hello('world');
await instance.helloAsync('Earth');
instance.noHook('stuff')
helloUnsubscriber();
instance.hello('Mars');
})();
/**
* Result:
*
* before hello world
* pre world
* Hello world
* post Hello world world
* after hello Hello world
* pre Earth
* Hello Earth async
* post Hello Earth async Earth
* No hook called with stuff
* pre Mars
* Hello Mars
* post Hello Mars Mars
*/Important
The @Hooks class decorator adds pre, post, and around methods to the decorated class. Any methods or properties with the same names in the class definition will be overridden.
If a pre or around function throws an error, the hooked method will throw the error as well. If a post function throws an error, the hooked method will not throw the error.
Registering a pre, post, or around function will result in an unsubscriber being returned. Invoking the unsubscriber will remove the function as a middleware.
Use Cases
- Put authorization and validation in
prefunctions - Put metrics in
aroundfunctions where applicable - Put any side effects such as notifications in
postfunctions
Best Practices
pre,post, andaroundfunctions should refrain from mutating any arguments in order to keep behavior predictable.- Use the
@Hookdecorator for synchronous methods. Make sure middleware functions for synchronous methods are also synchronous. - Use the
@HookAsyncdecorator for asynchronous methods.preandpostmiddleware functions for asynchronous methods can be synchronous or asynchronous.aroundmiddleware functions must be asynchronous