Aspect
Aspect
An aspect is a class annotated with the @Aspect()
annotation.
The purpose of an aspect is to encapsulate some cross-cutting concern in a single place so it can be applied anywhere simply by enabling the aspect.
An aspect is generally composed of one or more methods that is triggered at some places in the code, under some very specific conditions. These methods are called "advices".
import { AfterThrow, on } from '@aspectjs/core';
@Aspect()
export class LogErrorsAspect {
constructor(protected readonly logMethod = console.error) {}
// triggered when an error occurs
@AfterThrow(on.any.withAnnotations(LogErrors))
logErrorsAdvice(ctxt: AfterThrowContext, error: unknown) {
// log the error
this.logMethod(`Error in ${ctxt.target.label}: ${error}`);
// rethrow the original error
throw error;
}
}
Like any other class, an aspect can extend another class. If the parent class is also an aspect, the child aspect will inherit the advices from its parent.
@Aspect()
export class PromiseRejectAspect extends LogErrorsAspect {
constructor(logMethod = console.error) {
super(logMethod);
}
// inherits @AfterThrow(...) logErrorsAdvice()
// triggered after a method returns
@AfterReturn(on.methods.withAnnotations(LogErrors))
logErrorsAdvice(ctxt: AfterThrowContext, returnValue: unknown) {
if (returnValue instanceof Promise) {
// catch rejected promises as well
return (returnValue as Promise).catch((e) => {
this.logMethod(`Error in ${ctxt.target.label}: ${e}`);
return Promise.reject(e);
});
}
return returnValue;
}
}
Enable the aspect
An aspect has no effect until it has been enabled against the weaver.
The weaver is the component in AOP that combines aspects tgether with the codebase by applying the advices at specific points in the program's execution. It is recommended to enable the aspects all in once in a single file called aop.ts
.
import { getWeaver } from '@aspectjs/core';
import { LogErrorsAspect } from './log-errors.aspect';
getWeaver().enable(new LogErrorsAspect());