//

Friday, June 21, 2019

Middleware in Express

What is Middleware

The Middleware pattern is a series of processing units connected together, where the output of one unit is the input for the next one. In Node.js, this often means a series of functions in the form:
function(args, next) {
  // ... Run some code
  next(output) // Error or real output
}
The middleware pattern implements continuity. The request is coming from a client and a response is sent back to the client.
request->middleware1->middleware2->...middlewareN->route->response
Express has a middleware manager so developers only need to apply the middleware with app.use(). Take a look at this example:
var express = require('express')
var app = express()
//... Define middleware1-N
app.use(middleware1)
app.use(middleware2)
...
app.use(middlewareN)
...

Middleware Order

Middleware are executed in the order specified. In the following example, the logger('dev') middleware causes requests to be logged before the bodyParser.json() middleware causes payloads of requests to be parsed into request.body.
var logger = require('morgan')
var bodyParser = require('body-parser')
...
app.use(logger('dev'))
app.use(bodyParser.json())

Two Types of Express Middleware

There are two types of Express middleware:
  1. npm modules, e.g., body-parser from npm used with app.use(bodyParser.json())
  2. Custom middleware, e.g., app.use((req, res, next)=>{next()})
Developers can mix them. By utilizing middleware, developers can modularize their applications and reuse code.

Creating Middleware

Custom middleware is easy to create since it's just a function. Here's an example of creating a middleware and saving it as a variable which is used later to apply the middleware to the Express app:
const middleware = (request, response, next) => {
  // Modify request or response
  // Execute the callback when done
  next()
}
app.use(middleware)
Developers can also create middleware right in the app.use() call using an anonymous function definition:
app.use((request, response, next) => {
  // Modify request or response
  // Execute the callback when done
  next()
})
The first approach is better for modularizing because it's easier to move a named function or a function saved into a variable than an anonymous function.

Passing References

request is always the same object in the lifecycle of a single client request to the Express server. This allows us to implement a very useful pattern in which developers pass data from one middleware to another and to a request handler.
For example, developers can connect to a database in one middleware and make it available in all the subsequent middleware functions and request handlers (routes).
app.use(function (request, response, next) {  
  DatabaseClient.connect(URI, (err, db) => {
    // error handling
    request.database = db    
    next()
  })
})
In this middleware, database is available in the request object and we can run queries such as finding an application by the app ID:
app.use((req, res, next) => {
  req.database.collection('apps').findOne({appId: req.query.appId}, (err, app) => {
    // error handling
    req.app = app
    next()
  })
})
This makes moving routes and middleware to other files (modularization) straightforward, i.e., keeping code neat and organized.

Request Body

Typically an HTTP request body, a.k.a. payload, has information from a POST request when a client wants to create a new entity/record or update an existing one with PUT. Developers who implement servers, often need to access the request body information.
There's body-parser npm module which does just that. No need to code anything. Just install body-parser and enable the json() and urlencoded() middleware to convert raw form data into JSON.
So first, install body-parser with npm:
npm install body-parser
Then import middleware:
const bodyParser = require('body-parser')
And apply json to parse application/json type (that's what single-page applications and other JSON REST clients use):
app.use(bodyParser.json())
Usage: AJAX/XHR from single-page applications and other JSON REST clients.
Sometimes, the type could be different from application/json. For example, HTML web forms <form> with action attribute use application/x-www-form-urlencoded. And there's just such a middleware for parsing this type too:
app.use(bodyParser.urlencoded({extended: false}))
Usage: HTML web forms with action attribute.
Extended: false uses the querystring library while extended: true uses the qs library. The “extended:true” syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded.

Useful Middleware From npm

There are a lot of middleware modules to use. Every one of them is installed with the npm command using the module's npm name:
npm install <package_name> --exact
Here's the most popular and useful Express middleware which you'll probably end up using in almost every project (listed the npm names):
Express is a minimalistic framework. By using only the middleware you need for a particular project, you end up with a custom framework which is not bulky and doesn't have anything extra which your project doesn't need or use. The vast number of open-source middleware modules allows you to pick and choose and then modify the behavior of your application thanks to the flexible and configurable design of Express.
Feel free to print this list of commonly used Express middleware or download cheatsheet from GitHub.
Ref: 

No comments:

Post a Comment

Effective Branching Strategies in Development Teams

Effective Branching Strategies in Development Teams Effective Branching Strategies in Developme...