4 Middleware - Atlantis-Software/synapps Wiki

Overview

Middleware functions are functions that have access to the request object (req), and the next function in the application’s request-response cycle. The next function is a function in the Synapps router which, when invoked, executes the middleware succeeding the current middleware.

Middleware functions can perform the following tasks:

If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.

Example

Here is an example of a simple “Hello World” Synapps application. The remainder of this article will define and add two middleware functions to the application: one called myLogger that prints a simple log message and another called requestTime that displays the timestamp of the HTTP request.

var synapps = require('@synapps/core');
var app = synapps();

app.route('/', function(req) {
  req.resolve('hello world');
});

app.listen(3000);

Middleware function myLogger

Here is a simple example of a middleware function called “myLogger”. This function just prints “LOGGED” when a request to the app passes through it. The middleware function is assigned to a variable named myLogger.

var myLogger = function (req, next) {
  req.debug('LOGGED');
  next();
};

Notice the call above to next(). Calling this function invokes the next middleware function in the app. The next() function is not a part of the Node.js or Synapps API, but is the second argument that is passed to the middleware function. The next() function could be named anything, but by convention it is always named “next”. To avoid confusion, always use this convention.

To load the middleware function, call app.use(), specifying the middleware function. For example, the following code loads the myLogger middleware function.

var synapps = require('@synapps/core');
var app = synapps();

var myLogger = function (req, next) {
  req.debug('LOGGED');
  next();
};

app.use(myLogger);

app.route('/', function(req) {
  req.resolve('hello world');
});

app.listen(3000);

Every time the app receives a request, it prints the message “LOGGED” to the log.

The order of middleware loading is important: middleware functions that are loaded first are also executed first.

Middleware function requestTime

Next, we’ll create a middleware function called “requestTime” and add it as a property called requestTime to the request object.

var requestTime = function (req, next) {
  req.requestTime = Date.now();
  next();
};

The app now uses the requestTime middleware function. Also, the callback function of the root path route uses the property that the middleware function adds to req (the request object).

var synapps = require('@synapps/core');
var app = synapps();

var requestTime = function (req, next) {
  req.requestTime = Date.now();
  next();
};

app.use(requestTime);

app.route('/', function(req) {
  var responseText = 'Hello World!<br>'
  responseText += '<small>Requested at: ' + req.requestTime + '</small>'
  req.resolve(responseText);
});

app.listen(3000);

When you make a request to the root of the app, the app now displays the timestamp of your request in the browser.

Because you have access to the request object, the next middleware function in the stack, and the whole Node.js API, the possibilities with middleware functions are endless.

Configurable middleware

If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters.

File: my-middleware.js

module.exports = function(options) {
  return function(req, next) {
    // Implement the middleware function based on the options object
    next();
  };
};

The middleware can now be used as shown below.

var mw = require('./my-middleware.js');

app.use(mw({ option1: '1', option2: '2' }));