Middleware is a critical component of botpress. Simply put, it is a collection of functions that process messages. Think of it this way: everything that enters or leaves your bot is coming in to (or out from) the middleware.
If you have used Express before, botpress middleware is very similar to express's middleware.
Botpress has two middleware chains: incoming and outgoing
To receive messages: An installed module must send messages into the incoming middleware chain
To send messages: You (or a module) must send messages into the outgoing middleware chain and have a module able to send it to the right platform
Incoming: botpress-messenger connects to Facebook and receives messages from its built-in Webhook. It then sends messages into the incoming middleware, which your bot can process.
Outgoing: botpress-messenger listens (through a middleware function) for messages it can process on the outgoing middleware and sends them to Facebook through the Messenger Send API.
A middleware chain is simply a collection of middleware functions that are called in a predertermined order. Each middleware function in the chain has the freedom to:
- execute arbitrary code
- mutate the event
- call the next middleware
- interrupt the chain by never calling the next middleware (what we call swallowing the event)
- interrupt the chain by throwing an error
A middleware function is simply a function that takes an event as the first parameter and a next
function as the second parameter.
Here's an example of the 5 possible cases:
var middleware = function(event, next) {
// chain interruption (error)
if (internetDisconnected())
return next(new Error('Not connected'))
if (isUserBanned(event.user.id))
return // swallow the event
// arbitraty code execution
var translation = Translator.translate(event.text)
// event mutation
event.text = translation
// call next middleware function
next()
}
The return value of the middleware function can be anything or nothing, it isn't used.
You need to register a middleware function for botpress to know about it and use it. You may do so with the bp.middlewares.register
method:
// ** code taken from botpress-messenger **
bp.middlewares.register({
name: 'messenger.sendMessages', // friendly name
type: 'outgoing', // either incoming or outgoing
order: 100, // arbitrary number
handler: outgoingMiddleware, // the middleware function
module: 'botpress-messenger', // the name of the module, if any
description: 'Sends out messages that targets platform = '
+ 'messenger. This middleware should be placed at the end as it swallows events once sent.'
})
Once all middleware functions have been registered (usually modules should register middleware functions immediatly in their initialization), you must load them using bp.middlewares.load()
, which will create the incoming and outgoing chains automatically.
Once middleware functions are loaded, you'll see them displayed in your bot's interface:
By default, middleware functions are ordered by ascending order according to their order
property set on registration. The order can then be manually overwritten:
You can also re-order them programmatically using middleware function customizations.
Imagine you have a travel bot that is available on Facebook Messenger and Slack and that can handle many languages.
Your bot's installed modules would probably look a bit like:
- botpress-messenger for I/O with Facebook Messenger
- botpress-slack for I/O with Slack
- botpress-analytics to have an overview of how people use your bot
- botpress-translate (fictive) to translate incoming and outgoing messages
- ~/my-bot/private_modules/botpress-travel (fictive) your bot's travel logic goes here
Now lets look at how a complete interaction might be handled by your bot.
- A user types a message in French to your bot in Facebook Messenger
- Facebook pushes the message to your bot via the built-in botpress-messenger's Webhook
- botpress-messenger retrieves the user information and stores it in the built-in database
- botpress-messenger parses the message and calls the first incoming middleware function (botpress-analytics)
- botpress-analytics tracks the message then calls the next middleware function in the chain (botpress-translate)
- botpress-translate translates the message from French to English (by mutating it) then calls the next middleware function in the chain (botpress-travel)
- botpress-travel processes the message and responds by calling the
bp.messenger.sendText
method - botpress-messenger takes the response and calls the outgoing middlewares chain
- botpress-translate translates the message from English to French (by mutating it) then calls the next middleware function in the outgoing chain (botpress-analytics)
- botpress-analytics tracks the message then calls the next middleware function (botpress-messenger)
- botpress-slack will ignore the message because it doesn't know how to process messages with
type: facebook
- botpress-messenger sends the message to Facebook Messenger through the Send API
All of this happens behind the scene and is handled by the modules middleware. As a bot developer, all you have to worry about is writing the bot's logic.