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:
- npm modules, e.g.,
body-parser
from npm used withapp.use(bodyParser.json())
- 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):
- body-parser request payload
- compression gzip
- connect-timeout set request timeout
- cookie-parser Cookies
- cookie-session Session via Cookies store
- csurf CSRF
- errorhandler error handler
- express-session session via in-memory or other store
- method-override HTTP method override
- morgan server logs
- response-time
- serve-favicon favicon
- serve-index
- serve-static static content
- vhost: virtual host
- cookies and keygrip: analogous to
cookieParser
- raw-body: raw request body
- connect-multiparty, connect-busboy: file upload
- qs: analogous to
query
- st, connect-static analogous to
staticCache
- express-validator: validation
- less: LESS CSS
- passport: authentication library
- helmet: security headers
- connect-cors: CORS
- connect-redis
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