Writing LoopBack 4 Extensions

The LoopBack 4 Developer Preview #1 release is primarily targeted at extension developers. With this preview release, extension developers can start writing extensions for LoopBack 4. With LoopBack 4 being a complete rewrite from the ground up, extensibility was a key focus on the architecture. This better extensibility of the framework was achieved via @loopback/context which implements an Inversion of Control container and Dependency Injection.

LoopBack 4 extensibility makes writing extensions simpler than ever before. In this blog post, we’ll be going over writing an example log extension and seeing how easy it is to do so.

Log Extension Usage Scenario

Before we jump into writing an extension, let’s talk about what we’re going to build and why. A log extension provides a mechanism to debug a REST Application’s Controller methods by logging the inputs and the output produced. Below are the requirements for the log extension:

Log information to the console. Note: A more complex version would store logs in a file / database.

Mark Controller methods to be logged and the level at or above which they should be logged using a Decorator.

Set an application wide log level by binding it to our given key. Note: We’ll provide a default as well as a Mixin to make it easier to specify the binding.

A sequence action Provider that can be added to a sequence (this is what does the actual logging).

Support the following log levels, each higher than the previous: DEBUG < INFO < WARN < ERROR < OFF

Getting Started

Writing a LoopBack 4 extension is easy as there is a CLI tool to help create an extension project scaffolding. Install the CLI by running npm i -g @loopback/cli. Create an extension project by running lb4 extension and answering the prompts.

Keys

When writing an extension, you need a namespace for your keys. For this extension we’ll be using example.log.*. See implementation here: keys.ts.

Decorator

We want extension users to be able to select the Controller method they want to log as well as the level at which it should be logged. This can be accomplished through a decorator in LoopBack 4. Users will be able to mark their Controller method with @log() decorator OR @log(logLevel: number). If a user doesn’t specify the logLevel, the default of WARN will be used. See implementation here: log.decorator.ts.

Mixin

As part of our usage scenario, we want a user to be able to define the application-wide log level by binding a value to example.log.level. While it’s simple enough to do this binding, a Mixin can enable a better user experience. A Mixin allows a user to set the application wide log level by passing it into ApplicationOptions or via a “sugar” method app.logLevel(level: number). See implementation here: log-level.mixin.ts.

Providers

Providers enable most of the magic for an extension. For log extension, a few different providers will be needed based on the above usage.

A Provider for a sequence action that does the actual logging for decorated Controller methods based on their log level. This action also allows the user to optionally start the timer (implemented below). Implementation shown here: log-action.provider.ts.

A Provider for a timing function that can optionally be used to time the sequence for a response as shown here: timer.provider.ts.

Component

A component packages the extension so LoopBack 4 can automatically bind the providers to their respective keys. A user may override the key by binding a new value to it. Implementation shown here: component.ts.

That’s it! Writing a complex extension can be easy with LoopBack 4 by breaking it across multiple extension artifacts as we did for the log extension above.