Middlewares

This document explains how to call middlewares during message processing in Botfuel Dialog.

In the context of Web development, the term middleware usually refers to a function that provides additional processing at a specific point in the normal course of an application. In Botfuel Dialog, middlewares perform a similar function with two kinds of middlewares available: in middlewares and out middlewares.

Implementation

Middlewares are defined in the file src/middlewares.js of your bot. This file should export a list called in and a list called out.

You can define as many in and out middlewares as you want. Please note that they are executed in the same order as they are defined.

module.exports = {
  in: [
    async (context, next, done) => { /** middleware IN 1 */ },
    async (context, next, done) => { /** middleware IN 2 */ },
  ],
  out: [
    async (context, next, done) => { /** middleware OUT 1 */ },
  ],
};

Execution process and API

The execution process of middlewares is similar to the process in Hubot and Express. Each middleware can either continue the chain (by calling next) or interrupt the chain (by calling done).

If all middleware continues, the message is further processed and done is called afterwards.

Chat panel

If a middleware interrupts the chain, the normal processing of the message is skipped and done is called directly.

Chat panel

Middlewares are async functions with the following signature:

async (context, next, done) => {}

context

Data is passed through the parameter context to the middleware.

The parameter context follows this structure:

{
  botMessages '<a list of the bot messages>', // Only in "out" middlewares
  brain: '<the bot brain>',
  config: '<the bot config>',
  user: '<the user id>',
  userMessage: '<the user message>',
}

next

next is a function that should be called to continue on to the next middleware/continue normal message processing. next should be called with a single, optional argument: either the provided done function or a new function that eventually calls done. If the argument is not given, the provided done will be assumed.

done

done is a function that should be called to interrupt middleware execution and begin executing the chain of completion functions. done should be called with no arguments.

Middleware types

In middlewares

In middlewares are called just after a message has been received from the user but before the message is passed to the rest of the bot. If a middleware interrupts by calling done, the message is not passed to the bot.

Out middlewares

Out middlewares are executed when a dialog produced a list of bot responses to an incoming message, but before these messages are sent back to the messaging platform. If a middleware interrupts by calling done, the bot responses corresponding to the current dialog won't be sent. However, other bot responses can be produced by a subsequent dialog (for example, if the current dialog calls another dialog or in the case of multi-intent).

Examples

This example shows how to:

  • mute a bot based on specific conditions
  • log the time taken to generate all the responses to a user message
  • to record the exchanges between users and a bot
async function logBotAnswers(user, userMessage, botMessages) {
  ...
}
async function logEvent(eventType, timestamp) {
  ...
}

module.exports = {
  in: [
    async (context, next, done) => {
      const { user, brain } = context;
      const muted = await brain.userGet(user, '_isMuted');
      if (muted) {
        await done();
      } else {
        await next();
      }
    },
    async (context, next, done) => {
      await logEvent('received', Date.now());
      return next(async () => {
        await logEvent('processed', Date.now());
        await done();
      })
    },
  ],
  out: [
    async (context, next) => {
      const { user, userMessage, botMessages } = context;

      // Record the answers to a user message
      await logBotAnswers(user, userMessage, botMessages);

      return next();
    },
  ],
};

The package test-middlewares provides a complete usage example of middlewares.