— nodejs — 1 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.
Middleware functions take three arguments:
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
1/************************************************/2// Middleware - Simple request time logger3app.use((req, res, next) => {4 console.log(`${new Date().toLocaleString()} : ${request.method} url:: ${request.url}`);5 next(); 6});
In the below example,
/products
.1// Attach the express.json middleware to route "/products"2app.use('/products', express.json({ limit: 100 }))3
4// handle post request for path /products5app.post('/products', (request, response) => {6 const products = []7 const name = request.body.name 8 const brand = request.body.brand9 const category = request.body.category10 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
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 /products10app.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
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.
1// first function in the chain will check for JSON content2app.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.category10 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 /products18app.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
1/************************************************/2// Error handling Middleware functions3const errorLogger = (error, request, response, next) => {4 console.log( `error ${error.message}`) 5 next(error) // calling next middleware6}7
8const errorResponder = (error, request, response, next) => {9 response.header("Content-Type", 'application/json')10 11 const status = error.status || 40012 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// Routes22app.get('/products', async (request, response) => {23 try{24 const apiResponse = await axios.get("http://localhost:3001/products")25 const jsonResponse = apiResponse.data26 27 response.send(jsonResponse)28 }catch(error){29 next(error) // calling next error handling middleware30 }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 = 40045 throw error46})47
48/************************************************/49// Error Handling50app.use(errorLogger)51app.use(errorResponder)52
53// Catch all invalid route middleware54app.use(invalidPathHandler)55app.listen(PORT, () => {56 console.log(`Server listening at http://localhost:${PORT}`)57})
Below is promise-based error handling
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