Is it possible to use some sort of 'middleware' after sending the response with express? - node.js

The typical middleware in express is used before the request hits the routes, for example there's authentication first, then the code of the specific route is executed, then the response is sent.
I am wondering whether it is possible to have a thing like a middleware after a route is hit.
Say I have five routes that all respond with some json and I wanted to log the sent json everytime one of the routes is hit.
I could go and log manually everytime I send a response in a route, like this:
console.log(data);
res.json(data);
but this seems redundant to me. A better approach could be to wrap that in a function to call in the route, but that would require to pass the response object everytime like this:
/* instead of the above */
send(data, res);
/* and then somewhere else usable for all routes */
function send(data, res) {
console.log(data);
res.json(data);
}
this also seems a bit like bad practice to me, so I'm wondering whether this would be the preferred way or if there's a way to use some kind of 'middleware', which would allow to send the response in the usual way and hook in after that.

It is not really possible to attach a middleware which executes after the route, but you can execute a middleware, which binds a finish event on response,
app.use(function(req, res, next){
res.on('finish', function(){
// Do whatever you want this will execute when response is finished
});
next();
});
also https://stackoverflow.com/a/21858212/3556874

Related

How to add express middleware at the end of the chain that gets invoked no matter what (OK/FAIL responses)?

Is there a way to add middleware to the end of an express app or router chain that gets called to track whether or not the res / response was sent or not?
I mean, regardless of if:
A response is sent (string, JSON, etc.)
A static served file.
No file found in the static folder.
A catch-all callback was reached.
An error middleware was reached.
Example
For instance, if I wanted to log everything...
whether a response was successful or not, ie: it served a file via a express.static( ... ) middleware, some data fetched from a DB, or a custom middleware, or again... if it failed / threw an error...,
is there a way to invoke a callback at the very end?
So far from what I can understand, it seems like, by design, if a static file gets served successfully (via express.static), it doesn't call next(), so the chain stops there.
And for any custom-made middlewares using res.send(), you normally wouldn't want to call next() afterwards since it could cause some undesirable side-effects (errors with headers getting resent).
For error-handlers, that's easier since all unsuccessful responses can be caught here.
But how can it output both successful / unsuccessful responses? Could this be something that should be done without middlewares?
The solution I went with ended up being slightly different from this one by #idbehold, but in a nutshell, at the very top of the express app middleware chain, I had to hook a callback to the res Response object's finish event which gets triggered for most (all?) HTTP status-codes I needed to track a successfully served request.
app.use( ( req, res, next ) => {
res.on( 'finish', () => {
var codeStr = String( res.statusCode );
codeStr = codeStr[res.statusCode < 400 ? 'green' : 'red'];
var output = [req.method.green, req.fullUrl().green, codeStr];
trace( output.join( ' ' ) );
} );
next();
});
I can now get things like:
EDIT
Alright! So provided you also have an error-handler at the "end" of your middleware chain that serves something with an error 404 code, that will trigger the finish event on the res object.
Example of such an error-handler:
app.use( ( err, req, res, next ) => {
trace( "Error!".red );
trace( err );
res.status( 404 ).send(); // Triggers 'finish' on res.
})
There's a conceptual difficulty with the asynchronous architecture of node.js and Express for doing this. I'll describe the general problem and then discuss a few possible work-arounds.
First, each Express handler can be asynchronous. Thus, it gets called and returns pretty much immediately and nobody outside of that world knows whether it is still waiting for some asynchronous operation to finish before eventually sending its response or if it just failed to do anything. You literally can't tell from the outside world.
Second, you can monitor a given request to see if it either calls an error handler or if it sends a response. There is no way to monitor a request handler to see if it just failed to send anything because of the reason above - you have no way of knowing if its still waiting for some asynchronous thing to finish.
So, here's the best I could recommend:
Hook res.end() to see when it gets called. This is an indication that the response is now done (whether error or success). You can see an example of doing that in the express-afterware module that Medet linked in an above comment. The general idea is that you'd have your own middleware somewhere very early in the chain that overrides res.end() so you can see when its called. That early middleware would just install the override and call next() to continue the handler chain. Then, when the response is finished, your override would see that res.end() got called. This should work for all cases where the response is sent.
Then, you still need to handle cases where no response is sent (which is probably due to faulty code since all requests should get a response eventually). The only way I know of to do that is to implement some sort of timeout for a request. You can either use a built-in mechanism server.setTimeout() or you can implement your own inside your middleware (same middleware as describe in step 1). Then, after some timeout that you specify, if no response has yet been sent, you would take over and send some error response.
Install your own error middlewares early in the chain that will see and log all errors. Note that res.end() will still be called so the behavior in step 1 will still be triggered even for errors (error responses still call res.end()).
You can trigger a piece of code at the end of a request by using the finish event of the response object. The finish event is emitted when the response has been sent to the client and all the data has been flushed to the network.
app.use(function(req, res, next) {
res.on('finish', function() {
console.log('Request finished');
});
next();
});

Node.js cannot view headers inside middleware

I have a Node.js restful API. The problem I am having is that I am not sure why I am not able to see the request headers inside the middleware route.use(), however, it is visible inside get method router.get('/',function(req,res){}).
Can you someone please why is this case or what do I have to do get it visible inside
router.use(function(req,res,next){ next();});
Try something like his
router.use(function (req, res, next) {
console.log(req.headers['header_name']);
if (!req.headers['header_name']) return next('router')
next()
})
To skip the rest of the router’s middleware functions, call next('router') to pass control back out of the router instance.

How to push a sequence of html pages after one request using NodeJS and ExpressJS

I am turning around in stackoverflow without finding an answer to my question. I have used expressJS fur several days in order to make an access webpage that returns first an interstitial and then a webpage depending on several informations I can get from the requester IP and so on.
My first idea for the interstitial was to use this piece of code:
var interstitial = function(req, res, next) {
res.render('interstitial');
next();
}
router.get('/', interstitial, nextPage);
setting a timeout on the next nextPage callback function of router.get().
However it looks that I could not do that. I had an error "Error: Can't set headers after they are sent.". I suppose this is due to the fact that res.render already give a response to the request and in the philosophy of express, the next function is passing the req, res args for another reply to another function that possibly could do it. Am I right?
In that case, is there a way to give several answer, with timeout to one request? (a res.render, and after that in the next callback a rest.send...).
Or is this mandatory to force client to ask a request to give back another response? (using js on the client side for instance, or timers on client side, or maybe discussing with client script using socket.io).
Thanks
Not sure I fully understand, but you should be placing all your deterministic logic within the function of the handler you're using for your endpoint.
Kinda like so:
router.get('/', function(req, res){
var origin = request.origin;
if (origin == '11.22.33.44'){
res.send('Interstitial Page.');
}else{
res.send('Home Page');
}
});
You would replace the simple text responses with your actual pages, but the general idea is that once that endpoint is handled you can't next() it to secondary handler.

Express Request Post-Processing

I haven't been able to find anything in express's documentation, but is there such thing as request post processing? I am using a custom token authentication scheme using passport and I would like the ability to automatically update the token in a response header after making a request, mostly a hashed timestamp for authentication purposes. For discussion purposes, let's say I want the following function to execute after each request:
function requestPostProcess(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
}
Ideally, I'd like to be able to do this without having to call next() in each of my routes. Is that even possible?
If you want to add the token to the response,
1) You can create a middleware that adds the token as soon as the request comes, and before it is processed. Put this before request handlers.
Example,
app.use(function(req, res, next){
res.token = updateToken();
next();
})
The glitch here is that, the token will come with all the responses but that can be something you may accept, since it is a timestamp. Plus you can even handle errors using middlewares, and remove the token when the status is not 200.
Advantage: minimal changes required, with proper error handling it works great.
Disadvantage: it tells the time when request was received and not when the response was ready.
2) If you want to put the response after the process is completed, meaning the time when the response was ready, then you may need to create a utility function that sends back all the responses, and you always call that function. That utility function will check the status and appends the token.
function sendResponseGateway(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
res.send()
}
Now whenever you are ready to send response, you can call this function.
Disadvantage: function needs to be called everywhere and you will not be writing "res.send" anywhere.
Advantage :you have a gateway of sending response, you can do additional stuff like encoding, adding more headers etc. in that function and all those response modification stuff happens at one place.

Express middleware and parameter handling ordering on route

So I am running some API tests and I noticed that one test is failing because it is running some parameter handling logic before middleware, now here is an example of the route definition:
app.post("/something/:some_param",
middlewareA, middlewareB, middlewareC,
function(req, res) {
// Do stuff
});
Now I assumed (wrongly I think) that middleware would be invoked first then it would handle the parameter handler for :some_param however it seems to be the other way around. (by parameter handler I mean app.param())
Problem I have here is that if the above is correct and parameter handlers are run first, some of the logic within the parameter handler assumes the user is logged in already and blows up if they are not, and middlewareA handles user authentication and if they are not logged in redirects them etc, so ideally I would want middlewareA to be called first, so is there a way to achieve this ordering?
The only way I could see this working would be if the parameter handler could utilize middleware but there is no documentation on the API docs on this subject, so is there any best practice to handle this sort of scenario? as I do not want to have to shoe horn my middlewareA logic into my :some-param handling logic as I also have many other :other-param handlers etc which would also need this authentication (and other) middleware run before they run.
Yes, param handlers run before middleware. You can deal with this by either:
recoding your param handler as a middleware. There's not that much difference between the 2 mechanisms.
OR, in your param handler, just run the desired middleware directly as below:
.
function someParam(req, res, next, paramValue) {
myAuthMiddleware(req, res, function (error, result) {
if (error) {
next(error);
return;
}
//Here the user will be logged in
// do what you need to do with req and paramValue
next();
});
}

Resources