Skip to content

Use cases for intent based CRUD hooks

Benjamin Boudreau edited this page Mar 13, 2015 · 14 revisions

We recently received some feedbacks on the intent-based CRUD hooks.

There are issues and ideas raised. We would like to fully understand the use cases to decide what's the best way to enhance the hook apis, especially the ctx structure. Community input is critical to make the exercise successful. Please contribute your use cases below.

GitHub wiki does not support comments, let's keep the discussion in https://github.com/strongloop/loopback-datasource-juggler/issues/482.


There are different types of methods that trigger a hook function:

  1. prototype methods, such as updateAttributes, save, and delete. They work on a given model instance.
  2. static methods, such as create, updateAll, and deleteAll. They work on the a given model class.

A different taxonomy taking into account the database operation being performed:

  1. Methods that perform a full update of a single instance, i.e. they have all instance properties available and use them to replace the current data in the database. This includes both prototype methods like "save" and static methods like "create".

  2. Methods that perform a partial update of a single instance, i.e. "prototype.updateAttributes".

  3. Methods that perform a partial update of multiple instances, i.e. "updateAll".

  4. Methods that remove a single instance, i.e. "deleteById", "prototype.remove".

  5. Methods that perform a batch delete using a query - "deleteAll".

There are different purposes for hooks that @raymondfeng can see:

  1. In a before hook, perform additional operations.
  2. In a before hook, run some validations and fail fast.
  3. In a before hook, change/transform the input to the target DB operation.
  4. In a after hook, perform additional operations based on the outcome of the CRUD.
  5. In a after hook, change/transform the output from the target DB operation so that the callback/promise will receive a modified result.

Hooks typically need to read some information from the ctx object and write some information back to hook to influence downstream operations (another hook, the target method or error handler).

Use cases from Raymond:

  • Calculate a license key for a subscription record before it's save to the DB. The license key is derived from multiple properties of the subscription, such as userId, product, and expiration date.
MyModel.observe('before save', function(ctx, next) {
  var payload = {};
  var instance = ctx.instance || {};
  payload.userId = ctx.data.userId || instance.userId;
  payload.product = ctx.data.product || instance.product;
  payload.expirationDate = ctx.data.expirationDate || instance.expirationDate;
  ctx.data.licenseKey = generateLicenseKey(payload);
  next();
});
  • Automatically set the created and modified timestamps depending on if the intent is to create or update.
MyModel.observe('before save', function(ctx, next) {
  ctx.data.modified = new Date();
  if(!ctx.instance) {
    // Creating a new instance
    ctx.data.created = new Date();
  }
  next();
});
  • Hash the password for the user record.
  • Perform cascade deletion
  • Audit the changes to user model

Use cases from Fabien:

Use cases from Benjamin B:

  • Soft deletes: automatically adding isDeleted = false
  • Operations based on changed attributes (after hook using something like the new hookState) to de-normalization or do other operations based on the changed attributes
  • Limiting page size, forcing a limit

Use cases from JonnyBGod (João Ribeiro)

  • Perform cascade deletion including S3 object deletes "after delete"
  • Generate files "after create" (on example is generate a default sitemap in S3 when application is created)
  • Change services configurations and files "after save" existing document (some cases like S3 lifecycle rules)
  • Call processing functions "after save"
  • Pre populate related collections "after create"
  • Send verification email "after create"

From Líus Fontenelle:

  • Preferred use cases (in order of most used):

    • Logging/Tracking
    • Emit events
    • Offload async procedures via queues and/or redis, where jobs are:
      • Delete S3 objects
      • Processing data for reports
      • Update statistics
    • Send e-mails
    • Data push
  • Avoided use cases (most commonly when ACID-safety is required):

    • Cascade deletions
    • Soft delete
    • Audit log
    • Update timestamps
Clone this wiki locally