
Security News
High Salaries No Longer Enough to Attract Top Cybersecurity Talent
A survey of 500 cybersecurity pros reveals high pay isn't enough—lack of growth and flexibility is driving attrition and risking organizational security.
loopback4-authorization
Advanced tools
This directory contains source files for the mixins exported by this extension.
Sometimes it's helpful to write partial classes and then combining them together to build more powerful classes. This pattern is called Mixins (mixing in partial classes) and is supported by LoopBack 4.
LoopBack 4 supports mixins at an Application
level. Your partial class can
then be mixed into the Application
class. A mixin class can modify or override
existing methods of the class or add new ones! It is also possible to mixin
multiple classes together as needed.
class MyApplication extends MyMixinClass(Application) {
// Your code
}
// Multiple Classes mixed together
class MyApp extends MyMixinClass(MyMixinClass2(Application)) {
// Your code
}
For hello-extensions we write a simple Mixin that allows the Application
class
to bind a Logger
class from ApplicationOptions, Components, or .logger()
method that is mixed in. Logger
instances are bound to the key
loggers.${Logger.name}
. Once a Logger has been bound, the user can retrieve it
by using
Dependency Injection
and the key for the Logger
.
A Logger class is provides a mechanism for logging messages of varying priority by providing an implementation for
Logger.info()
&Logger.error()
. An example of a Logger isconsole
which hasconsole.log()
andconsole.error()
.
class ColorLogger implements Logger {
log(...args: LogArgs) {
console.log('log :', ...args);
}
error(...args: LogArgs) {
// log in red color
console.log('\x1b[31m error: ', ...args, '\x1b[0m');
}
}
A complete & functional implementation can be found in logger.mixin.ts
. Here
are some key things to keep in mind when writing your own Mixin.
A Mixin constructor must take an array of any type as it's argument. This would
represent ApplicationOptions
for our base class Application
as well as any
properties we would like for our Mixin.
It is also important for the constructor to call super(args)
so Application
continues to work as expected.
constructor(...args: any[]) {
super(args);
}
ApplicationOptions
As mentioned earlier, since our args
represents ApplicationOptions
, we can
make it possible for users to pass in their Logger
implementations in a
loggers
array on ApplicationOptions
. We can then read the array and
automatically bind these for the user.
class MyApp extends LoggerMixin(Application) {
constructor(...args: any[]) {
super(...args);
}
}
const app = new MyApp({
loggers: [ColorLogger],
});
To implement this, we would check this.options
to see if it has a loggers
array and if so, bind it by calling the .logger()
method. (More on that
below).
if (this.options.loggers) {
for (const logger of this.options.loggers) {
this.logger(logger);
}
}
.logger()
As mentioned earlier, we can add a new function to our Application
class
called .logger()
into which a user would pass in their Logger
implementation
so we can bind it to the loggers.*
key for them. We just add this new method
on our partial Mixin class.
logger(logClass: Logger) {
const loggerKey = `loggers.${logClass.name}`;
this.bind(loggerKey).toClass(logClass);
}
Logger
from a Component
Our base class of Application
already has a method that binds components. We
can modify this method to continue binding a Component
as usual but also
binding any Logger
instances provided by that Component
. When modifying
behavior of an existing method, we can ensure existing behavior by calling the
super.method()
. In our case the method is .component()
.
component(component: Constructor<any>) {
super.component(component); // ensures existing behavior from Application
this.mountComponentLoggers(component);
}
We have now modified .component()
to do it's thing and then call our method
mountComponentLoggers()
. In this method is where we check for Logger
implementations declared by the component in a loggers
array by retrieving the
instance of the Component
. Then if loggers
array exists, we bind the
Logger
instances as normal (by leveraging our .logger()
method).
mountComponentLoggers(component: Constructor<any>) {
const componentKey = `components.${component.name}`;
const compInstance = this.getSync(componentKey);
if (compInstance.loggers) {
for (const logger of compInstance.loggers) {
this.logger(logger);
}
}
}
Now that we have bound a Logger to our Application via one of the many ways made
possible by LoggerMixin
, we need to be able to retrieve it so we can use it.
Let's say we want to use it in a controller. Here's an example to retrieving it
so we can use it.
class MyController {
constructor(@inject('loggers.ColorLogger') protected log: Logger) {}
helloWorld() {
this.log.log('hello log');
this.log.error('hello error');
}
}
.logger()
methodclass LoggingApplication extends LoggerMixin(Application) {
constructor(...args: any[]) {
super(...args);
this.logger(ColorLogger);
}
}
class LoggerApplication extends LoggerMixin(Application) {
constructor() {
super({
loggers: [ColorLogger],
});
}
}
class LoggingComponent implements Component {
loggers: [ColorLogger];
}
const app = new LoggingApplication();
app.component(LoggingComponent); // Logger from MyComponent will be bound to loggers.ColorLogger
FAQs
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A survey of 500 cybersecurity pros reveals high pay isn't enough—lack of growth and flexibility is driving attrition and risking organizational security.
Product
Socket, the leader in open source security, is now available on Google Cloud Marketplace for simplified procurement and enhanced protection against supply chain attacks.
Security News
Corepack will be phased out from future Node.js releases following a TSC vote.