Cloud Docs Home > F5 Application Services Proxy Index

Middleware Architecture and API Reference

The Application Services Proxy (ASP) uses middleware to provide proxy functionality (similar to Express.js). The routing framework invokes this middleware to handle data events and transaction lifecycles.

Middleware functions use transaction objects (like request and response) and subsequent functions in the middleware stack to control the transaction lifecycle. The middleware stack consists of a set of middleware functions, which collectively provide the complete proxy application. Each function implements a subset of the proxy functionality.

Middleware HTTP Stack

The ASP has a built-in middleware HTTP stack, shown in the diagram below.

When the routing layer receives a client request, it:

  • sends the request through the connection manager, load balancer, header manipulator, and forwarder (the forward stack); then
  • send the request to the real server.

Middleware functions in the forward stack can register callbacks to invoke when traffic returns from the backend server.

When the routing layer receives a response from the backend server, it:

  • invokes the forward-stack callbacks in order of registration,
  • passes the response through the header manipulator and forwarder (the reverse stack), then
  • sends the response to the client.
Diagram showing the ASP's built-in middleware stack. Client requests pass from the routing layer to the connection manager, load balancer, header manipulator, and forwarder in turn before reaching the real server. The server response passes from the routing layer to the header manipulator and fowarder before reaching the client.

Middleware HTTP API

Use the ASP Middleware HTTP API to define HTTP proxy middleware functions.

Note

The APIs described here are experimental and may change in future versions (including minor version releases).

Intercept HTTP request

interceptHttpReq(req, res[, reqNextCb])
Arguments:
  • req – <http.IncomingMessage> The HTTP Request object received from the client. Use to inspect/update client request properties like headers, url, method, etc., and inspect/transform the request body.
  • res – <http.ServerResponse> Use to send a response to the client.
  • CallbackreqNextCb(err, req, resCb) Calls the next middleware function to pass control/terminate the stack.
reqNextCb(err, req[, resCb])
Arguments:

Middleware can tell the routing layer about errors by invoking reqNextCb with a non-null err. When the middleware stack receives a non-null err, the stack terminates and subsequent middleware in the forward stack are not invoked. The routing layer sends the client an HTTP response with the 503 status code.

The routing layer passes the req object in reqNextCb as the input argument to the next middleware function. If reqNextCb has no arguments, or has no req argument, the routing layer passes the req argument from the preceding middleware to the next middleware in stack. If there is no req argument in the preceding middleware, the routing layer passes the original client request.

A middleware can invoke reqNextCb(req) in the following ways:

  • req can be the input request object passed to the middleware or a transformed version of it.
  • A new HTTP request to the backend real-server (such as <http.ClientRequest>) object as req argument. This is typically done by the last middleware in the stack (forwarder provides this functionality in built-in stack) after all preceding middleware in the stack transforms the client request.
  • The req argument as null terminates the middleware stack. In this case the middleware passing null is responsible for handling/sending the client response else the client response object remains hanging.

Examples

Request Header Manipulation

This example shows a middleware function adding headers to the incoming client request.

function interceptHttpReq(req, res, reqNextCb) {
  req.headers['X-forwarded-for'] = 'foo';
  reqNextCb();
}
Respond to client and terminate forward stack

This example shows a middleware function that responds to the client directly and terminates the forward stack.

function interceptHttpReq(req, res, reqNextCb) {
  //Consume or drain req
  req.on('data', function(chunk) {
    // Do something interesting with the data
  });
  req.on('end', function() {
    res.write('Responding to client');
    res.end();
    //Terminates the chain
    reqNextCb(null, null);
  });
}
Error termination

This example shows a middleware that inspects the header and throws an error when header foo is bar or calls next middleware function otherwise.

function interceptHttpReq(req, res, reqNextCb) {
  if req.headers['foo'] = 'bar' {
    err = new Error('Responding to Client');
    reqNextCb(err, null);
  } else {
    reqNextCb(null, req);
  }
}

Intercept HTTP Response

The routing layer invokes the Intercept HTTP response middleware function when the proxy receives a new HTTP server response. This function has access to server response and the next middleware function to pass control/terminate the reverse stack.

resCb(res[, resNextCb])
Arguments:

A forward middleware can define this callback function and pass it as the resCb argument to the reqNextCb function invocation. The routing layer inserts this callback in the reverse stack initiated when the proxy receives the response from the backend server.

resNextCb(err, res)``()
Arguments:

The resNextCb, like reqNextCb, is the function invoked by middleware to inform the routing layer about how to handle the execution of the reverse stack.

The middleware can inform the routing layer of any errors encountered by invoking resNextCb with a non-null err. On receiving a non-null err. the middleware stack terminates and subsequent middleware in reverse stack are not invoked. The routing layer sends the client an HTTP response with the 503 status code.

The routing layer passes the res object in resNextCb as the input argument to the next middleware function. When resNextCb has no arguments, or no res argument, the routing layer passes the res argument from the preceding middleware to the next middleware in the reverse stack. If no middleware sets the res argument, the routing layer uses the original server response.

A middleware can invoke resNextCb with the res argument in the following ways:

  • The res argument can be the input response object passed to the middleware, or a transformed version of it.
  • The res argument passed as null terminates the middleware stack. In this case, the middleware passing null is responsible for handling/sending the client response; otherwise, the client response object remains hanging. In the ASP built-in stack, forwarder middleware is responsible for sending the response to the client and terminating the reverse stack.

Examples

The examples below define an interceptHttpReq which registers the callback resCb. When the proxy receives the server response, it invokes the callback.

Response Header Manipulation

This example shows a middleware that appends a header to the server response.

function interceptHttpReq(cliReq, cliRes, reqNextCb) {
  resCb = function(res, resNextCb) {
    res.headers['X-Server'] = 'bar';
    resNextCb();
  };
  reqNextCb(null, cliReq, resCb);
}
Respond to client and terminate reverse stack

This example shows a middleware that responds to the client and terminates reverse stack.

function interceptHttpReq(cliReq, cliRes, reqNextCb) {
  resCb = function(res, resNextCb) {
    // Consume or drain proxyRes
    res.on('data', function(chunk) {
      // Do something interesting with the data
    });
    res.on('end', function() {
      cliRes.write('Responding to Client');
      cliRes.end();
      // Terminates the chain
      resNextCb(null, null);
    });
  }
  reqNextCb(null, cliReq, resCb);
}