How and When to Use Loopback Hooks!

Loopback is a node framework based on Express which provides the CRUD to accelerate high value features creation. However, these basic functions may not answer to your needs or partially. For example, you might want to send a mail to the owner of an object when you save it, or update another related object.

Hooks can, and will, help you achieving this.

What’s a hook and its application cases?

Using hooks has the following advantages:

  • DRY principle, only one hook declaration instead of several function calls
  • Uncoupling
  • Separate trade logic from program requirements

A hook is a special event handler. It is bound to events of the framework or program you are using. As such, it is used to alter, augment or replace the behavior of the target.

You should use hooks to perform systematic operations such as:

  • mail sending
  • data sanitization (formatting, filtering…)
  • logging
  • security checks (encoding, decoding, signing…)

Closer look and examples

If several hooks are attached to the same event, they are executed one after the other in the order of their declaration.
Loopback gives access to three types of hooks: connector, remote and operation.

Connector hooks

If you don’t know what a connector is in Loopback, I suggest you read this.

connector_hook_flow

There are two of them:

  • 'before execute'
  • 'after execute'

The first is called before you make use of a connector, the second when you receive the response from it.

You must always finish your hook by calling next() or ctx.end(), if you don’t, your server will hang. Using next() goes to the next observer whereas ctx.end() ends the observed event. You can see it in the schema on the right.

This category of hooks can be used to log access and queries to your database. Another application would be the formatting of the input/output of your calls to a remote API. For instance, I used the after execute to catch 5XX errors of an API before they are caught and rewritten by a firewall:

myRestConnector.observe('after execute', function(ctx, next) {
  if (/^5/.test(ctx.res.statusCode)) {
    var error = new Error();
    error.status = 400;
    return ctx.end(error, null)
  }
  return next();
});

Remote hooks

  • beforeRemote()
  • afterRemote() and afterRemoteError(), only one of these two is called after a remote.

You can use those to do security checks, for example verify access rights, to sanitize your remote input or whitelisting your output. Mostly, it comes handy when the built-in remotes of Loopback do not meet your needs.

Wild cards are allowed in the remote name so you can bind a handler to a set of remotes.

Express

Since Loopback is built on express app.use() is available. It is the easiest way to bind a single handler to remotes with a similar path, but attached to different models.

app.use('/\*/stats', function (req, res, next) {
  console.log("I match /aModelWithStats/stats and /anotherModelWithStats/stats");
  return next();
});

Operation hooks

These hooks are directly related to built-in functions of Loopback such as save, delete or find.

They are useful when you need to update relations of a model you just saved, or to log access and modifications on some instance and then warn the owner by mail.

The documentation is quite exhaustive. However I would like to underline that afterInitialize is different from the other operation hooks since it is synchronous. So be careful not to write a heavy function for this handler.

The following example sends a mail if a new instance of MyModel is saved.

MyModel.observe('after save', function(ctx, next) {
  if (ctx.instance && ctx.isNewInstance) {
    let myMessage = { content: 'this is some badass content' };
    myMailingService.send(myMessage);
  }
  return next();
}

Conclusion

I hope this article helped you understand the added value of hooks and that it will give you tools to improve the overall quality of your project.
If you have any question, or remarks about usage, please share them in the comments section below!