Skip to content

Latest commit

 

History

History
240 lines (174 loc) · 12.1 KB

middleware.md

File metadata and controls

240 lines (174 loc) · 12.1 KB

What is middleware?

Express Middleware is nothing more than a function with one of two signatures: function (request, response, next), or function (error, request, response, next). Let's talk about the first, and most basic signature first.

The request object provides all the details about the user's request, including any data they've provided. As an example of what middleware typically does, the fluid.express.middleware.bodyparser.json and fluid.express.middleware.bodyparser.urlencoded grades included with this package inspect the original request, break down information found there, and add variables that present the same data in a more usable form. See below for details.

The response object gives you a way to send information (headers, content) back to the user. A lot of what we refer to as middleware in this package doesn't make use of the request, but the original request will only receive a response if some piece of middleware eventually makes use of the response object.

The next function gives your middleware control over whether processing should continue. At the time it is given a chance to process a request, each piece of middleware is aware of the next piece of middleware in the chain. It can do one of three things with this:

  1. Not call the next function (ending the conversation, presumably after sending something to the user using the response object).
  2. Call the next function with an error argument (see "Error Handling Middleware" below), indicating that an error was encountered by this piece of middleware.
  3. Call the next function with no arguments, allowing the next piece of middleware to start its work.

Error Handling Middleware

A middleware function with the alternate signature function (error, request, response, next) is designed to respond to an error passed to the next function by a piece of upstream middleware. Once an error is thrown, only middleware with this signature is given the chance to respond. As with the above, each piece of error handling middleware has the chance to decide whether to allow additional error handlers to respond after it has completed its work. To allow downstream error handlers to respond, a piece of errorMiddleware must pass along the error it received, typically by calling next(error)

Ordering Middleware by Priority

As each link in the chain gets to decide whether the remaining links will even get to see a particular request, the order in which middleware is called is very important. This package uses namespaces and priorities to control the order in which middleware is called.

Unless you are only working with a single router or piece of middleware, it is strongly recommended that you use this mechanism to ensure that your middleware is called at the right time. Take a look at this example, which might be found inside a fluid.express or fluid.express.router instance:

components: {
    cookie: {
        type: "fluid.express.middleware.cookieparser",
        options: {
            priority: "first"
        }
    },
    session: {
        type: "fluid.express.middleware.session",
        options: {
            priority: "after:cookie"
        }
    },
    router: {
        type: "my.router.grade",
        options: {
            priority: "after:session"
        }
    }

}

In this example, we have explicitly ordered our middleware. First, we ensured that cookies are parsed first, so that the session middleware will be able to find its cookie and look up the user's data. We have also placed our router after all middleware, to ensure that our router only sees requests that already have cookie and session data.

Note that we were only able to use priorities like after:session and after:cookie because the "wrapper" grades included with this package include priorities. When writing your own middleware or routers, best practice is to include a distinct namespace option in your grade definition.

Middleware Components Included in This Package

fluid.express.middleware

The base grade you will extend to define your own middleware. An instance of fluid.express or fluid.express.router will automatically attempt to wire a component with this grade name into itself. To use this grade, you must implement the middleware invoker (see below).

Component Options

Option Type Description
method {String} This grade provides the ability to limit itself to only operate on requests that match a particular HTTP method. Support lowercased string values, such as get, post, put, or delete. Defaults to use, or "any method".
path {String} or {Array} Which part(s) of the relative URL space this router wants to work with. May contain wildcards and path variables. Defaults to /, or "any path".
namespace (optional) {String} The namespace to use when ordering other middleware relative to this one, as in after:<namespace>.
priority (optional) {String} The priority of this middleware relative to other pieces of middleware (see "Ordering Middleware by Priority" above).

Please note that although middleware may also be limited to a particular method or path, it does not do any routing at all to child components. Only the middleware itself will be given the chance to work with an appropriate response. Routing is only handled by fluid.express and fluid.express.router components.

Component Invokers

{that}.middleware(request, response, next)
  • request {Object} An Express Request object (see the docs for details).
  • response {Object} An Express Response object (see the docs for details).
  • next: The next Express middleware or router function in the chain.
  • Returns: Nothing.

This function is called when your middleware is given the chance to work with an individual request. An invoker definition for standard middleware might look something like:

invokers: {
  middleware: {
    funcName: "your.namespaced.function",
    args: ["{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2"] // request, response, next
  }
}

If you want to define a middleware that handles errors (see above), you would simply use a different invoker definition, as in:

invokers: {
  errorMiddleware: {
    funcName: "your.namespaced.errorFunction",
    args: ["{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2", "{arguments}.3"] // error, request, response, next
  }
}

For a reference example of an error handler, see the "error handler" middleware docs.

fluid.express.middleware.wrappedMiddleware

The base grade for all "wrapped" third-party middleware, such as fluid.express.middleware.cookieparser, fluid.express.middleware.urlencoded and fluid.express.middleware.json (see below).

Component Options

Option Type Description
middlewareOptions {Object} The configuration options to pass on to the underlying third-party middleware.
middlewareImpl {Function} The underlying third-party middleware function which will field all requests.

Component Invokers

{that}.middleware(request, response, next)
  • request {Object} An Express Request object (see the docs for details).
  • response {Object} An Express Response object (see the docs for details).
  • next: The next Express middleware or router function in the chain.
  • Returns: Nothing.

Passes through request, response, and next to the underlying middleware implementation, which is expected to be found at middleware.options.middlewareImpl. You must provide your own middlewareImpl to use this grade, as demonstrated in the following example:

var fluid = require("infusion");
fluid.require("%fluid-express");

fluid.require("third-party-middleware", require, "my.middleware.npm.thirdPartyMiddleware");

fluid.defaults("my.middleware.wrapper", {
    gradeNames: ["fluid.express.middleware.wrappedMiddleware"],
    middlewareImpl: "@expand:my.middleware.npm.thirdPartyMiddleware({that}.middlewareOptions)"
});

This example assumes that the third-party-middleware package exports its constructor, and that it accepts configuration options as its only argument. The expander will take care of creating the middlewareImpl option, and the middleware invoker will use this middleware to handle incoming requests.

fluid.express.middleware.cookieparser

Parses client cookie headers and makes them available via request.cookies. Wraps the standard cookie parser middleware previously bundled with Express.

Component Options

Option Type Description
middlewareOptions {Object} The configuration options to pass on to cookie parser middleware. See the cookie-parser docs for more details.
middlewareOptions.secret {Object} The only required configuration option within the above. Defines a secret key that will be used to sign the session cookie.

fluid.express.middleware.json

Parses JSON data passed by the client and makes it available via request.body. Wraps part of the body parser middleware previously bundled with Express.

Component Options

Option Type Description
middlewareOptions {Object} The configuration options to pass on to the underlying JSON body parser instance.

fluid.express.middleware.session

Parses client session cookies makes server-side session data associated with the cookie available via request.sesssion. Wraps the standard session middleware previously bundled with Express. Requires the cookieparser middleware above to be in the middleware chain before it.

Component Options

Option Type Description
middlewareOptions {Object} The configuration options to pass on to the underlying express-session instance.
middlewareOptions.secret {Object} The only required configuration option within the above. Defines a secret key that will be used to sign the session cookie.

fluid.express.middleware.urlencoded

Parses URL encoded data passed by the client and makes it available via request.query. Wraps part of the body parser middleware previously bundled with Express.

Component Options

Option Type Description
middlewareOptions {Object} The configuration options to pass on to the underlying JSON body parser instance.

fluid.express.middleware.error

See the "error handler" middleware documentation.

fluid.express.middleware.headerSetter

See the "header setter" middleware documentation.

fluid.express.middleware.contentAware

See the contentAwareMiddleware documentation.

fluid.express.middleware.requestAware

See the requestAwareMiddleware documentation.

fluid.express.middleware.redirect

See the "redirect" middleware documentation.