Skip to content
bobby_dreamer

NodeJS Middlewares

nodejs1 min read

Middleware in ExpressJS are functions that come into play after the server receives the request and before the response is processed by the route and sent to the client.

We can use middleware functions for different types of preprocessing tasks required for fulfilling the request like database querying, making API calls, preparing the response and also calling the next middleware function in the chain.

We call app.use() to add a middleware function to our Express application. Express executes middleware in the order they are added.

Difference between Controllers Vs. Middleware ?

  1. Controllers - An entity that will actually respond to the requests.
  2. Middleware - A step in progression towards actioning your request. Middleware are often reused more than once in multiple routes and often they do not respond to request(respond by returning to client with some data).

Middleware functions take three arguments:

  • the request object (request)
  • the response object (response)
  • optionally the next() middleware function.

An exception to this rule is error handling middleware which takes an error object as the fourth parameter. The next() function is a function in the Express router that, when invoked, executes the next middleware in the middleware stack. If next() is not called, the request will be left hanging.

Code: Available in GitHub

In the below example, we are adding a middleware which will be called for all routes

index.js
1/************************************************/
2// Middleware - Simple request time logger
3app.use((req, res, next) => {
4 console.log(`${new Date().toLocaleString()} : ${request.method} url:: ${request.url}`);
5 next();
6});

In the below example,

  1. We are attaching the express.json() middleware by calling the app.use() function. It parses incoming requests with JSON payloads and is based on body-parser. We have also configured a maximum size of 100 bytes for the JSON request.
  2. This middleware function will be called only for this route /products.
index.js
1// Attach the express.json middleware to route "/products"
2app.use('/products', express.json({ limit: 100 }))
3
4// handle post request for path /products
5app.post('/products', (request, response) => {
6 const products = []
7 const name = request.body.name
8 const brand = request.body.brand
9 const category = request.body.category
10
11 console.log(name + " " + brand + " " + category)
12 ...
13})

You can make a POST request to http://localhost:3000/ with header set to content-type: application/json and body {"name":"furniture", "brand":"century", "price":1067.67}


In the below example, the middleware checks if the request contains a json content

index.js
1const requireJsonContent = (request, response, next) => {
2 if (request.headers['content-type'] !== 'application/json') {
3 response.status(400).send('Server requires application/json')
4 } else {
5 next()
6 }
7}
8
9// handle post request for path /products
10app.post('/products', requireJsonContent, (request, response) => {
11 ...
12 ...
13 response.json(
14 {productID: "12345",
15 result: "success")}
16 );
17})

Another example, handle get request with 3 middleware functions

index.js
1app.get('/users', (request, response, next) => {
2 console.log("Stage 1 processing ");
3 next()
4},
5(request, response, next) => {
6 console.log("Stage 2 processing ");
7 next();
8},
9(request, response) => {
10 response.send('response for GET request');
11});

In the next example, we can see multiple middleware functions are added to a route to preprocess in multiple stages.

index.js
1// first function in the chain will check for JSON content
2app.use('/products', requireJsonContent)
3
4// second function will check for valid product category
5// in the request if the first function detects JSON
6app.use('/products', (request, response) => {
7
8 // Allow to add only products in the category "Electronics"
9 const category = request.body.category
10 if(category != "Electronics") {
11 response.status(400).send('Server requires application/json')
12 } else {
13 next()
14 }
15 })
16
17// handle post request for path /products
18app.post('/products',
19 (request, response) => {
20
21 ...
22 ...
23 response.json(
24 {productID: "12345",
25 result: "success"})
26 })

In the below example, we add middleware for error handling

index.js
1/************************************************/
2// Error handling Middleware functions
3const errorLogger = (error, request, response, next) => {
4 console.log( `error ${error.message}`)
5 next(error) // calling next middleware
6}
7
8const errorResponder = (error, request, response, next) => {
9 response.header("Content-Type", 'application/json')
10
11 const status = error.status || 400
12 response.status(status).send(error.message)
13}
14
15const invalidPathHandler = (request, response, next) => {
16 response.status(400)
17 response.send('invalid path')
18}
19
20/************************************************/
21// Routes
22app.get('/products', async (request, response) => {
23 try{
24 const apiResponse = await axios.get("http://localhost:3001/products")
25 const jsonResponse = apiResponse.data
26
27 response.send(jsonResponse)
28 }catch(error){
29 next(error) // calling next error handling middleware
30 }
31})
32
33// handle get request for path /
34app.get('/', (request, response) => {
35 response.send('response for GET request');
36})
37
38app.post('/products', requireJsonContent, (request, response) => {
39 ...
40})
41
42app.get('/productswitherror', (request, response) => {
43 let error = new Error(`processing error in request at ${request.url}`)
44 error.statusCode = 400
45 throw error
46})
47
48/************************************************/
49// Error Handling
50app.use(errorLogger)
51app.use(errorResponder)
52
53// Catch all invalid route middleware
54app.use(invalidPathHandler)
55app.listen(PORT, () => {
56 console.log(`Server listening at http://localhost:${PORT}`)
57})

Below is promise-based error handling

index.js
1app.get('/product', (request, response, next) => {
2
3 axios.get("http://localhost:3001/product")
4 .then(response=>response.json)
5 .then(jsonresponse=>response.send(jsonresponse))
6 .catch(next)
7})

Thanks for reading