I want to have a middleware like Express log request summary end of each route
=>
[POST] /books/commentpart 200 1435.472 ms - 35
I want to log more data in end of each request. But I do not know how to write middleware like this. I have tried a middleware function after all route but it not worked. In each router, I also pass next() call.
app.use(responseTime());
//router
app
.use(users(app, db))
.use(dataLogs(app, db))
.use(category(app, db));
//log middleware
app.use(function(req, res, next) {
var data = {};
var method = req.method;
if(method == 'GET'){
data = req.query;
} else {
data = req.body;
}
var resTime = res.getHeader('X-Response-Time');
log.debug(' [ ' + iduser + ' ] - ' + req.route.path + ' - ' + resTime + ' : ' + JSON.stringify(data));
});
module.exports = app;
So, middlewares, when registered (using app.use, app.all, or etc.) are a queue of rules that apply to incoming requests. Note that this registration happens at the server-start time and is a part of the server itself, not requests.
Once it's all set up and the server is running, any hop (step in the queue, a.k.a middleware) after the first one is called only if the previous hop has called next() explicitly. In other words, if you put a app.use((req, res, next) => {}); at the beginning of all the middlewares, the server is gonna do absolutely nothing! -- this middleware is just swallowing any incoming request and not calling next().
Problem
Now the problem is, how can you register a middleware that:
Applies to all rules, AND
Runs after all the other middlewares
Satisfying the second requirement is not easy. Because as we mentioned above the last hop in this rules queue runs only when all the previous ones have gracefully called next() one after another. And sometimes it doesn't happen for various reasons, including simply forgetting to call next()! And it's hard to enforce people to do that.
Solution
I need to mention what #robertklep said in a comment above bolder. It's using on-finished on res! https://github.com/jshttp/on-finished
Example:
// have this before all the other middlewares
app.use((req, res) => {
console.log("I'll be the first line executed, almost ever!");
onFinished(res, (err) => {
console.log("and I'll be the last one, knowing response"
+ " code which is already sent is: " + res.statusCode);
});
};
What this does is, actually listening on when the response is finished (you can alternatively use on-headers). So it's a whole new dimension of doing a job on express, prependicular to the existing middlewares queue mechanism. Just be careful and enjoy! ;)
middleware is just a function that do something and then pass the request to the next function using "next()". So if you really want to do that you need to catch all of your routes in the same route something like this
app.all('*', (req, res) => {
// do something before
// your async code here
// do something after
});
Finally it worked. Actually, in some routes, i forgot pass next() in the end of each router.
Now i do another method, utilizing responseTime function and it works perfectly without add next() to all every routes. Thanks all!
app.use(responseTime(function (req, res, time) {
var data = {};
var method = req.method;
if(method == 'GET'){
data = req.query;
} else {
data = req.body;
}
log.info(method, iduser, req.path, ' - ', Math.round(time), 'ms', ' : ', JSON.stringify(data));
}))
Related
Until now I've defined my get and post handlers with just (req, res) as arguments, with the assumption being that I put these handlers last in the chain of middleware, and make sure that I handle any responses and error handling properly within these handlers... hence it doesn't matter that I don't make any reference to next.
Is this a valid and sensible approach, or is it good practice always to call next() even if (at present) there is nothing coming afterwards? For example, perhaps in the future you might want to do some handling after these routes... or maybe there's a reason I haven't yet come across why it's good practice to always call next().
For example, there is the following simple example in the express routing guide:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
Of course, I appreciate that this is a very simple example to illustrate that handlers can be chained, and is not intended to provide a complete framework for a get handler, but would it be better to define and use next even in the second handler, as follows?
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res, next) {
res.send('Hello from B!')
next()
})
Or is it actually common practice to assume that a handler function that sends a response back to the client should not call next()... i.e. the assumption should be that the chain will end at the handler that actually sends the response?
Or is there no established practice on this point?
I'm even wondering whether it might be common not to send any response in the get handler but to defer that to a dedicated response handler coming after... by which I mean an OK response handler rather than an error response handler (for which it seems to be common practice to defined a final error handler and call next(err)). So, in a non-error situation, you would call next() and in the following middleware you would do your res.status(200).send(req.mydata) where req.mydata is added in your get handler.
No. You should only call next() if you want something else to handle the request. Usually it's like saying that your route may match that request but you want to act like it didn't. For example you may have two handlers for the same route:
app.get('/test', (req, res, next) => {
if (something) {
return next();
}
// handle request one way (1)
});
app.get('/test', (req, res) => {
// handle request other way (2)
});
Always the first matching handler is called, so for the GET /test request the first handler will be called, but it can choose to pass the control to the second handler, as if the first didn't match the request.
Note that if the second handler doesn't intend to pass the request to the next handler, it doesn't even have next in its arguments.
If there was no second handler, then the standard 404 handler would be used if the first one called next().
If you pass an argument to next() then an error handling middleware will be called.
My rule of thumb is to handle the response in the handler if you're going to give a 20x (Success) response code, and in centralized error handling if not. That looks something like this in practice:
// ./routes/things.js
const express = require('express');
const Thing = require('../models/thing');
const Router = express.Router();
// note, the handlers might get pulled out into a controllers file, if they're getting more complex.
router.param('thingId', (req, res, next, id) => {
Thing.findById(id, (e, thing) => {
if (e) return next(e);
// let's say we have defined a NotFoundError that has 'statusCode' property which equals 404
if (!bot) return next(new NotFoundError(`Thing ${id} not found`));
req.thing = thing;
return next();
});
});
router.get('/', (req, res, next) => {
// possibly pull in some sort, limit, and filter stuff
Thing.find({}, (e, things) => {
if (e) return next(e);
res.send(things);
});
});
router.route('/:thingId')
.get((req, res) => {
// if you get here, you've already got a thing from the param fn
return res.send(req.thing);
})
.put((req, res, next) => {
const { name, description } = req.body; // pull whitelist of changes from body
let thing = req.thing;
thing = Object.assign(thing, { name, description }); // copy new stuff into the old thing
thing.save((e) => {
if (e) return next(e);
return res.send(thing); // return updated thing
});
});
Keeping each logical chunk in its own file can reduce repetition
// ./routes/index.js then mounts the subrouters to the main router
const thingsRoute = require('./things');
const express = require('express');
const router = express.Router();
/* .... other routes **/
router.use('/things', thingsRoute);
Error handling is then centralized, and can be mounted either in its own file or right on the app:
// in ./index.js (main app entry point)
const express = require('express');
// this will require by default ./routes/index.js
const routes = require('./routes');
const app = express();
const log = require('./log');// I prefer debug.js to console.log, and ./log.js is my default config file for it
/* ... other app setup stuff */
app.use(routes);
// you can mount several of these, passing next(e) if you don't handle the error and want the next error handler to do so.
app.use((err, req, res, next) => {
// you can tune log verbosity, this is just an example
if (err.statusCode === 404) {
return res.status(404).send(err.message);
}
log.error(err.message);
log.verbose(err.stack); // don't do stack traces unless log levels are set to verbose
return res.status(500).send(err.message);
});
In Express middleware, it should be taking 3 parameters: request, response, next.
However, in the 2nd middleware in the code where I copied from a book, but only use request, response. What is the reason here? and is next optional?
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response, next) {
console.log("In comes a " + request.method + " to " + request.url);
next();
});
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello, world!");
});
http.createServer(app).listen(3000);
next() is called when you want the routing for this request to continue onto the next middleware or the next route handler for this request. It is common to have more than one middleware that might examine a given request so if you did not send a response and want normal routing to continue for this request, then you would call next() when you were done with your processing and you want routing to continue.
If you have already sent a response and thus do not want routing to continue, then you do not call next().
It is up to you whether you declare the parameter next or not. If you never intend to call it, then you don't need to declare it as a parameter (it is still passed, but you don't have to declare it if you're not going to use it).
So, you can declare your middleware/requeset handler with parameters req and res like this:
app.use("/someRoute", function(req, res) {
res.send("hello");
});
Or, with parameters req, res and next like this:
app.use("/someRoute", function(req, res, next) {
if (req.query.x) {
// don't handle this request here, let some other route
// handler following this handle it
next();
} else {
// send the response, no more route handlers after this
res.send("hello");
}
});
It makes no difference to Express whether you declare the next argument or not. If you plan on using it, then declare it. If you don't plan on using it, then there is no reason to declare it, but it is passed anyway. This is true of all Javascript function arguments. If you don't declare all the arguments as named arguments, it just makes it harder to access them, but they are still there (for completeness, then can still be accessed through the arguments object).
There's also a special case route handler with four arguments (err, req, res, next) which is used for error handling (when next(err) is called), but that's not what your question is about. Express does treat route handlers with four arguments declared differently. It registers them as error handlers.
With express.js there are 4 types of basic handlers.
2 - req, res
3 - req, res, next
4 - err, req, res, next
If you have 2 arguments, express will always assign a req and res to them, no matter what you call them. It's just a calling convention that is widely used by the express community that makes for cleaner, readable and understandable code.
I am unable to send the res (request object) between functions. The following code is executed by my app.js (main express middleware):
//app.js calls File.js
//File1.js
var file2 = require('./File2.js);
export.modules = function (req,res,next) {
file2(data) {
res.send(data); //<-- this is not working
}
}
//File2.js
export.modules = function(data){
data = 'test';
}
Also I do not understand when to use next() or when to use res.end().
Its really hard to understand from you code snippets, so i will address your second question regarding next vs send
You use next inside your middlewares, which means you dont want yet to respond to your client with data, but you want to proccess the data from another middleware down the line, when you reach your final middleware you need to use res.send();
note that you cannot use res.send multiple times, so you must call it when you finished your processing and want to respond the data to the user.
you must use middleware with express as following:
var app = express();
app.use(function(req,res, next){
// some proccessing
req.proccessData = "12312312";
next();
})
app.use(function(req,res, next){
// here you respond the data to the client
res.send(req.proccessData);
})
You can also use this with routes(get, post and etc...) Just add next as third param to the route when you want to send data to next stage
There are a few posts on this question but none that answers the issue directly, head-on. Let me clarify that I understand (or so I think) the use of next(), next('route'), return next(), return and their impact on control flow.
My entire middleware for the app consists of a series of app.use, as in:
app.use(f1);
app.use(f2);
app.use(f3);
app.use(f4);
...
In each of these middlewares, I have possibility of sending the response and be done without any need for further processing. My problem is that I am unable to stop the processing from going to the next middleware.
I have a clumsy work around. I just set a res.locals.completed flag after sending a response. In all the middlewares, at the very start, I check this flag and skip processing in the middleware if the flag is set. In the very first middleware, this flag is unset.
Surely, there must be a better solution, what is it? I would think that Express implicitly would do this checking and skip the middlewares through some express-specific method?
According to the express documentation on http://expressjs.com/guide/using-middleware.html
If the current middleware does not end the request-response cycle,
it must call next() to pass control to the next middleware,
otherwise the request will be left hanging.
so if a middleware needs to end the request-response early, simply do not call next() but make sure that the middleware really ends the request-response by calling res.end, res.send, res.render or any method that implicitely calls res.end
app.use(function (req, res, next) {
if (/* stop here */) {
res.end();
} else {
next();
}
});
Here is an example server showing that it works
var express = require('express');
var app = express();
var count = 0;
app.use(function(req, res, next) {
console.log('f1');
next();
})
app.use(function(req, res, next) {
console.log('f2');
if (count > 1) {
res.send('Bye');
} else {
next();
}
})
app.use(function(req, res, next) {
console.log('f3');
count++;
next();
})
app.get('/', function (req, res) {
res.send('Hello World: ' + count);
});
var server = app.listen(3000);
you will see the after 3 requests, the server shows "Bye" and f3 is not reached
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 am wondering if there is a documented method I should be considering first.
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.
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);
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.
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);
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
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.)
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.