Proper way to remove middleware from the Express stack?
Asked Answered
I

7

28

Is there a canonical way to remove middleware added with app.use from the stack?

It seems that it should be possible to just modify the app.stack array directly, but I wonder if there is a documented method I should consider first.

Indecorum answered 3/9, 2013 at 22:33 Comment(2)
@elmigranto That's an overly simplistic view. There are plenty of reasons why you might want to use Express routing in a more dynamic way, which may require adding/removing middleware in certain cases.Indecorum
The middlewares stack is in app._router.stackBraud
M
25

use actually comes from Connect (not Express), and all it really does is push the middleware function onto the app's stack.

So you should be just fine splicing the function out of the array.

However, keep in mind there is no documentation around app.stack nor is there a function to remove middleware. You run the risk of a future version of Connect making changes incompatible with your code.

Maxfield answered 3/9, 2013 at 23:33 Comment(1)
Or express making changes incompatible with your code. express is no longer dependent on connect, so I don't think this works anymore.Grantor
B
8

This is a useful functionality if you are inheriting some unwanted middleware from a framework built on express.

Building on some of the answers that came before me: In express 4.x the middleware can be found in app._router.stack. Note that the middleware are invoked in order.

// app is your express service

console.log(app._router.stack)
// [Layer, Layer, Layer, ...]

Tip: You can search the individual layers for the one you want to remove/move

const middlewareIndex = app._router.stack.findIndex(layer => {
 // logic to id the specific middleware
});

Then you can just move/remove them with standard array methods like splice/unshift/etc

// Remove the matched middleware
app._router.stack.splice(middlewareIndex, 1);
Bluenose answered 7/3, 2019 at 22:30 Comment(1)
Quick note: the underscore indicates that app._router is intended to be private, i.e not part of the public API, and could therefore change between releases. This should probably only be used as a last resort, but it is certainly doable. Thanks for the good explanation though.Liscomb
D
7

There seems to be no built in way to do that, but you can manage to get the same result with a small trick. Create your own array of middleware (let's call it dynamicMiddleware) but don't push that into express, instead push just 1 middleware that will execute all the handlers in dynamicMiddleware asynchronously and in order.

const async = require('async')

// Middleware 
const m1 = (req, res, next) => {
    // do something here 
    next();
}

const m2 = (req, res, next) => {
    // do something here 
    next();
}

const m3 = (req, res, next) => {
    // do something here 
    next();
}

let dynamicMiddleware = [m1, m2, m3]

app.use((req, res, next) => {
    // execute async handlers one by one
    async.eachSeries(
        // array to iterate over
        dynamicMiddleware, 
        // iteration function
        (handler, callback) => {
            // call handler with req, res, and callback as next
            handler(req, res, callback)
        }, 
        // final callback
        (err) => {
            if( err ) {
            // handle error as needed

            } else {
                // call next middleware
                next()
            }
        }
    );
})

The code is a bit rough as I don't have a chance to test it right now, but the idea should be clear: wrap all dynamic handlers array in 1 middleware, that will loop through the array. And as you add or remove handlers to the array, only the ones left in the array will be called.

Disregard answered 13/11, 2016 at 18:7 Comment(2)
This doesn't necessarily solve the issue. At least in my use case, having different handling of mount points and methods is important. It seems that modifying the internal stack is still possible, it's just been moved around a bit.Indecorum
Can you please clarify your use case in more detail. Perhaps you can wrap this in a small module and reuse at different mounting points?Disregard
B
2

No way of removing a middleware as far as I know. however, you can assign a boolean flag to 'deactivate' a middleware at anytime you want.

let middlewareA_isActivate = true;
// Your middleware code
function(req, res, next) {
   if (!middlewareA_isActivate) next();
   // .........
}
// Deactivate middleware
middlewareA_isActivate = false;

EDIT :
After reading through ExpressJs (4.x) code, I notice that you can access the middlewares stack via app._router.stack, manipulation goes from there I guess. Still, I think this 'trick' might not be able to work in future Express
P/s: Not tested how Express behaves when manipulate the middlewares stack directly though

Braud answered 16/11, 2016 at 3:22 Comment(0)
A
2

You can use the express-dynamic-middleware to make this.

https://github.com/lanbomo/express-dynamic-middleware

Use it like this

const express = require('express');

// import express-dynamic-middleware
const dynamicMiddleware = require('express-dynamic-middleware');


// create auth middleware
const auth = function(req, res, next) {
    if (req.get('Authorization') === 'Basic') {
        next();
    } else {
        res.status(401).end('Unauthorization');
    }
};

// create dynamic middleware
const dynamic = dynamicMiddleware.create(auth);

// create express app
const app = express();

// use the dynamic middleware
app.use(dynamic.handle());

// unuse auth middleware
dynamic.unuse(auth);
Althing answered 13/5, 2018 at 15:48 Comment(0)
S
0

Following from the hints above, I've add success with the following on express 4.x. My use case was logging what was coming in with Slack Bolt, so I could capture and then mock it:

// Define a handy function for re-ordering arrays
Array.prototype.move = function(from, to) {
  this.splice(to, 0, this.splice(from, 1)[0]);
};

// Use the normal use mechanism, so that 'extra' stuff can be done
// For example, to log further up the order, use app.use(morgan("combined"))
app.use([my-middleware]); 

// Now adjust the position of what I just added forward
const numElements = app._router.stack.length;
app._router.stack.move(numElements - 1, 1);

You can use console.log("Stack after adjustment", app._router.stack) to confirm the new order is what you want. (For Slack Bolt, I had to use app.receiver.app because the Bolt app wraps the express app.)

Subito answered 21/8, 2019 at 11:13 Comment(0)
B
-2

We can write like this.

// route outside middleware

route.get("/list", (req, res)=>{
    res.send("from listing route");  
});

//use middleware

router.use(Middlewares.AuthMiddleware.isValidToken);

//routes inside the middleware

route.post("/create", (req, res)=>{
    res.send("from create route");  
});

route.delete("/delete", (req, res)=>{
    res.send("from delete route");  
});

So basically, write routes before injecting middleware into your route.

Biannulate answered 27/4, 2020 at 12:18 Comment(1)
This doesn't answer the question.Indecorum

© 2022 - 2024 — McMap. All rights reserved.