Skip to content

Instantly share code, notes, and snippets.

@changhengliou
Last active May 17, 2019 10:12
Show Gist options
  • Select an option

  • Save changhengliou/1449850e32d76cadc5328aaad9a86714 to your computer and use it in GitHub Desktop.

Select an option

Save changhengliou/1449850e32d76cadc5328aaad9a86714 to your computer and use it in GitHub Desktop.
AOP implementation with ES6 Proxy
class BaseController {
constructor () {
this.ctx = {
status: 200,
body: {}
};
const before = this.before || (() => {
console.log(`Before run`);
return true;
});
const after = this.after || (() => {
console.log(`After run`);
})
const handleError = this.handleError || this.setError;
// traverse through entire prototype chain, and register proxy on every business logic function
let currProto = this;
while (true) {
Object.getOwnPropertyNames(currProto).filter(prop => {
return !(
// only register proxy on function, ignore constructor, and our predefined method: before, handleError and after
typeof currProto[prop] !== 'function' ||
currProto.constructor.name === 'Object' ||
currProto.constructor.name === 'BaseController' ||
prop === 'before' ||
prop === 'after' ||
prop === 'handleError' ||
prop === 'constructor'
);
})
.forEach((prop) => {
console.log(`Attach proxy to ${currProto.constructor.name}.${prop}`)
const func = this[prop];
Object.defineProperty(this, prop, {
get: () => new Proxy(func, {
apply: (target, thisArg, argList) => {
const validateSuccess = before();
if (!validateSuccess) {
handleError.apply(thisArg, argList);
after.apply(thisArg, [validateSuccess]);
return;
}
const result = target.apply(thisArg, argList);
after.apply(thisArg, [validateSuccess]);
return result;
}
})
})
})
if (!(currProto = Object.getPrototypeOf(currProto))) {
break
}
}
}
validate (rules, data) {
const errors = this.app.validator.validate(rules, data)
if (!errors) {
return true
}
const fields = errors.reduce((previous, current) => {
previous[current.field] = current.message
return previous
}, {})
const error = new Error('Invalid Fields')
error.fields = fields
error.status = 422
this.setError(error)
return false
}
setSuccess (msg, status = 200) {
this.ctx.body = {
message: msg,
status: status
}
}
setError (error) {
try {
throw Error(error)
} catch (err) {
this.ctx.status = 500
this.ctx.body = {
message: err.message
}
}
}
}
const signUpRules = () => {
return Math.random() > 0.5;
}
class Controller extends BaseController {
before () {
console.log('Before validation...')
return signUpRules();
}
after (result) {
console.log(this.ctx);
if (!result) {
console.log('Validation Failed, abort.');
return;
}
console.log('Done');
}
login () {
console.log('login in process...');
this.setSuccess("Apply login", 201);
}
}
var b = new BaseController();
var c = new Controller();
c.login();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment