Reputation: 26615
Does express
provide a way to specify that a middleware always runs at the end of the chain?
I want to create a pair of middleware functions, one at the start, and one at the end, which gather up analytics about the call.
I know I can do something like this:
app.use(entry);
app.get("/some-endpoint", (req, res, next) => {
res.send("hello").end();
next();
});
app.use(exit);
Where entry()
and exit()
are my middleware.
However, there are two things I don't like about this solution. First, is that next()
has to be called or else the exit()
middleware won't be used.
The other is that I would prefer to instead build a Router
that can be used as one piece and just work. Something like:
// MyRouter.js
const router = () => Router()
.use(entry)
.use(exit);
export default router;
// myServer.js
import router from './MyRouter.js';
import express from 'express';
const app = express();
app.use(router());
app.get("/some-endpoint", (req, res) => {
res.send("hello").end();
});
Being able to bundle it all up in to one thing that always runs would make it a lot more usable.
Upvotes: 5
Views: 2064
Reputation: 19428
Since the res
object in Express wraps http.ServerResponse
, you can attach a listener for the 'finish'
event in a middleware. Then when the response is "finished", exit()
will be called as soon as the event fires.
// analyticMiddleware.js
const analyticMiddleware = (req, res, next) => {
// Execute entry() immediately
// You'll need to change from a middleware to a plain function
entry()
// Register a handler for when the response is finished to call exit()
// Just like entry(), you'll need to modify exit() to be a plain function
res.once('finish', () => exit)
// entry() was called, exit() was registered on the response return next()
return next()
}
module.exports = analyticMiddleware
// myServer.js
import analytics from './analyticMiddleware.js';
import express from 'express';
const app = express();
app.use(analytics);
app.get("/some-endpoint", (req, res) => {
res.send("hello").end();
});
Upvotes: 10