Cloud Docs Home > F5 Application Services Proxy Index

Event Handlers

Event handlers are JSON strings triggered in the Application Services Proxy (ASP) data path that can augment/by-pass the ASP’s built-in middleware. To define event handlers for an ASP instance(s), add a JSON blob to the virtual server section of the ASP configuration.

Important

The JSON code defining event handlers must be correctly escaped as valid strings.

Insertion Logic

The ASP wraps event handler code in a custom module wrapper and compiles the code to access the user exported functions. The virtual server middleware stack loads the event handler functions before its built-in functions. This ensures event handlers run before the transaction objects (request, response) reach the built-in middleware stack.

Custom Module Wrapper

The ASP’s event handler module wrapper is a customized version of the Node.js module wrapper. The ASP adds an additional scoped log object to the function wrapper. This log object enables event handler code to log interesting messages.

As with any other Node.js module, you need to export the function that you want to register as the event handler. For example:

function (exports, require, module, __filename, __dirname, log) {
  // User code lives here
  module.exports = function eventHandler(...) {
  // Exported event handler function code lives in here
  }
});

The ASP sets the module name for every event handler to a unique identifier. The identifier consists of

  • the virtual server ID defining the event handler,
  • its index position in the event handlers list, and
  • the event name.

The example below shows configuration block that contains a list of event handlers for a particular virtual server and their corresponding module names.

let event-handlers-list = [
{
  "http-request": "module.exports = function RequestHandler(){}",
  // module name: <virtual-server-id>-0-http-request.js

  "http-response": "module.exports = function ResponseHandler(){}"
  // module name: <virtual-server-id>-0-http-response.js
 },
 {
   "http-request": "module.exports = function RequestHandler(){}",
   // module name: <virtual-server-id>-1-http-request.js

   "http-response": "module.exports = function ResponseHandler(){}"
   // module name: <virtual-server-id>-1-http-response.js
 }
];

Note

The unique module names appear in log messages and stack traces.

Event handler logging

The ASP uses the Winston logging framework to log messages to the console. The ASP prefixes event handler log objects with the unique module identifier. This makes it easier to determine the source of log messages.

The example below shows ASP log output. The log message on the third line is identifiable by the unique module name printed from the event handler: vs1-0-http-request.js.

2017-09-12T21:08:29+00:00 - info: [ASP 22285] No stats section in configuration
2017-09-12T21:08:29+00:00 - info: [ASP 22285] No endpoint discovery configuration, using static
2017-09-12T21:08:30+00:00 - info: [ASP 22285 - vs1-0-http-request.js] Log message from event handler

Event handlers have the same logging levels available in the ASP global config. Event handlers can use methods provided on the log object - described in the Winston API - to log messages to the console.

Supported Modules

Event handlers can require Node.js core modules. They can’t require or use external NPM modules.

Supported Events

Event: http-request

The proxy invokes event handlers for http-request events when it receives a new HTTP client request. Use the Intercept HTTP Request API to write an http-request event handler.

As noted in the Middleware API documentation, the http-request object can register a callback to invoke in the reverse stack called when the ASP receives a response from the backend server.

The diagram below shows an http-request event handler inserted in the forward stack, where it triggers before the built-in middleware.

A diagram illustrating that the HTTP request event handler fires at the top of the forward stack, before the built-in middleware.

In the diagram below, the event handler registers a response callback, which invokes before the built-in middleware in the reverse stack.

A diagram illustrating that a response callback registered by the HTTP request event handler fires at the top of the reverse stack, before the built-in middleware.

Event: ‘http-response’

Use the Intercept HTTP Response API to write an http-response event handler. The proxy invokes http-response event handlers when it receives a new HTTP response from the backend server.

The diagram below shows an http-response event handler inserted in the reverse stack, where it triggers before the built-in middleware.

A diagram illustrating that the HTTP response event handler fires at the top of the reverse stack, before the built-in middleware.

Examples

The example below demonstrates how to define a list of event handlers in the virtual-server section of the ASP config.

Important

The event handlers fire in the middleware stack in the same order in which they appear in the ASP config.

  1. The first group defines an http-request event handler.
  2. The second group defines an http-request event handler with a response callback. This group also defines a log message using a Node.js core module.
  3. The third group defines an http-response event handler.
"event_handlers": [
     {"http-request": "module.exports = (req, res, next) => { \
                             // checks if the request path is correct else terminates
                             if (!(req.url === '/' || req.url === '/index.html')) { \
                               res.statusCode = 404; \
                               res.end('Incorrect request url'); \
                             } else { \
                               next(); \
                             } \
                           }"
      },
     {"http-request": "module.exports = (cliReq, cliRes, next) => { \
                               const util = require('util'); \
                               function setResHeaderCallBack(res, next) { \
                                 res.headers['x-my-bar1'] = 'foo1'; \
                                 let msg = util.format('Adding Response header %s = %s', 'x-my-bar1', 'foo1'); \
                                 log.info(msg); \
                                 next(); \
                               } \
                               // Registers http-response callback
                               next(null, cliReq, setResHeaderCallBack); \
                           }"
     },
     {"http-response": "module.exports = (res, next) => { \
                               res.headers['x-my-bar2'] = 'foo2'; \
                               next(); \
                           }"
     }
]